如何正确使用Python中的多处理模块?
How to properly utilize the multiprocessing module in Python?
我尝试从 110 个 PDF 文件中提取图像。提取图像后,我想删除所有重复项并删除小于 4KB 的图像。我的代码如下所示:
def extract_images_from_file(pdf_file):
file_name = os.path.splitext(os.path.basename(pdf_file))[0]
call(["pdfimages", "-png", pdf_file, file_name])
os.remove(pdf_file)
def dedup_images():
os.mkdir("unique_images")
md5_library = []
images = glob("*.png")
print "Deleting images smaller than 4KB and generating the MD5 hash values for all other images..."
for image in images:
if os.path.getsize(image) <= 4000:
os.remove(image)
else:
m = md5.new()
image_data = list(Image.open(image).getdata())
image_string = "".join(["".join([str(tpl[0]), str(tpl[1]), str(tpl[2])]) for tpl in image_data])
m.update(image_string)
md5_library.append([image, m.digest()])
headers = ['image_file', 'md5']
dat = pd.DataFrame(md5_library, columns=headers).sort(['md5'])
dat.drop_duplicates(subset="md5", inplace=True)
print "Extracting the unique images."
unique_images = dat.image_file.tolist()
for image in unique_images:
old_file = image
new_file = "unique_images\" + image
shutil.copy(old_file, new_file)
这个过程可能需要一段时间,所以我开始涉足多线程。随意将其解释为我说我不知道自己在做什么。我认为这个过程在提取图像方面很容易并行化,但不能进行重复数据删除,因为一个文件有很多 I/O 正在进行,我不知道该怎么做。所以这是我在并行过程中的尝试:
if __name__ == '__main__':
filepath = sys.argv[1]
folder_name = os.getcwd() + "\all_images\"
if not os.path.exists(folder_name):
os.mkdir(folder_name)
pdfs = glob("*.pdf")
print "Copying all PDFs to the images folder..."
for pdf in pdfs:
shutil.copy(pdf, ".\all_images\")
os.chdir("all_images")
pool = Pool(processes=8)
print "Extracting images from PDFs..."
pool.map(extract_images_from_file, pdfs)
print "Extracting unique images into a new folder..."
dedup_images()
print "All images have been extracted and deduped."
提取图像时似乎一切正常,但随后一切都变得一团糟。所以这是我的问题:
1) 我是否正确设置了并行进程?
2) 它是否继续尝试在 dedup_images()
上使用所有 8 个处理器?
3) 有什么我遗漏的 and/or 没有做对吗?
提前致谢!
EDIT 这就是我所说的 "haywire" 的意思。错误以这样的一堆行开始:
I/O Error: Couldn't open image If/iOl eE r'rSourb:p oICe/onOua l EdNrner'wot r Y:oo prCekon u Cliodmunan'gttey of1pi0e
l2ne1 1i'4mS auogbiepl o2fefinrlaee e N@'egSwmu abYipolor ekcn oaCm o Nupentwt y1Y -o18r16k11 8.C1po4nu gn3't4
y7 5160120821143 3p4t7I 9/49O-8 88E78r81r.3op rnp:gt ' C
3o-u3l6d0n.'ptn go'p
en image file 'Ia/ ON eEwr rYoorr:k CCIoo/uuOln dtEnyr' rt1o 0ro2:p1 e1Cn4o uiolmidalng2'eft r m '
ai gpceoo emfn iapl teN e1'w-S 8uY6bo2pr.okpe nnCgao' u
Nnetwy Y1o0r2k8 1C4o u3n4t7y9 918181881134 3p4t7 536-1306211.3p npgt'
4-879.png'
I/O Error: CoulId/nO' tE rorpoern: iCmoaugled nf'itl eo p'eub piomeangae fNielwe Y'oSrukb pCooeunnat yN e1w0 2Y8o1r
4k 3C4o7u9n9t8y8 811032 1p1t4 3o-i3l622f pt 1-863.png'
然后像这样多行变得更具可读性:
I/O Error: Couldn't open image file 'pt 1-864.png'
I/O Error: Couldn't open image file 'pt 1-865.png'
I/O Error: Couldn't open image file 'pt 1-866.png'
I/O Error: Couldn't open image file 'pt 1-867.png'
这会重复一段时间,在乱码错误文本和可读文本之间来回切换。
终于到了这里:
Deleting images smaller than 4KB and generating the MD5 hash values for all other images...
Extracting unique images into a new folder...
这意味着代码会恢复并继续该过程。可能出了什么问题?
- 是的,Pool.map接受一个带有 1 个参数的函数,然后是一个列表,其中的每个元素都作为参数传递给第一个函数。
- 不,因为除了
extract_images_from_file()
的正文,你在这里写的所有内容都在运行原始过程中。另外,我要指出您使用的是 8 个 进程 ,而不是 处理器 。如果您碰巧拥有 8 核英特尔 CPU,启用超线程,您将能够同时 运行 16 个进程。
- 我觉得不错,除了如果
extract_images_from_file()
抛出异常,它会破坏你的整个 Pool
,这可能不是你想要的。为防止这种情况,您可以尝试绕过该块。
与您打交道的 "haywire" 的性质是什么?我们可以看到异常文本吗?
你的代码基本没问题。
乱码是所有试图将不同版本的 I/O Error
消息交错写入控制台的进程。错误消息是由 pdfimages
命令生成的,可能是因为当您 运行 两个同时发生冲突时,可能是因为临时文件,或者两者都使用相同的文件名或类似名称。
尝试为每个单独的 pdf 文件使用不同的图像根目录。
我尝试从 110 个 PDF 文件中提取图像。提取图像后,我想删除所有重复项并删除小于 4KB 的图像。我的代码如下所示:
def extract_images_from_file(pdf_file):
file_name = os.path.splitext(os.path.basename(pdf_file))[0]
call(["pdfimages", "-png", pdf_file, file_name])
os.remove(pdf_file)
def dedup_images():
os.mkdir("unique_images")
md5_library = []
images = glob("*.png")
print "Deleting images smaller than 4KB and generating the MD5 hash values for all other images..."
for image in images:
if os.path.getsize(image) <= 4000:
os.remove(image)
else:
m = md5.new()
image_data = list(Image.open(image).getdata())
image_string = "".join(["".join([str(tpl[0]), str(tpl[1]), str(tpl[2])]) for tpl in image_data])
m.update(image_string)
md5_library.append([image, m.digest()])
headers = ['image_file', 'md5']
dat = pd.DataFrame(md5_library, columns=headers).sort(['md5'])
dat.drop_duplicates(subset="md5", inplace=True)
print "Extracting the unique images."
unique_images = dat.image_file.tolist()
for image in unique_images:
old_file = image
new_file = "unique_images\" + image
shutil.copy(old_file, new_file)
这个过程可能需要一段时间,所以我开始涉足多线程。随意将其解释为我说我不知道自己在做什么。我认为这个过程在提取图像方面很容易并行化,但不能进行重复数据删除,因为一个文件有很多 I/O 正在进行,我不知道该怎么做。所以这是我在并行过程中的尝试:
if __name__ == '__main__':
filepath = sys.argv[1]
folder_name = os.getcwd() + "\all_images\"
if not os.path.exists(folder_name):
os.mkdir(folder_name)
pdfs = glob("*.pdf")
print "Copying all PDFs to the images folder..."
for pdf in pdfs:
shutil.copy(pdf, ".\all_images\")
os.chdir("all_images")
pool = Pool(processes=8)
print "Extracting images from PDFs..."
pool.map(extract_images_from_file, pdfs)
print "Extracting unique images into a new folder..."
dedup_images()
print "All images have been extracted and deduped."
提取图像时似乎一切正常,但随后一切都变得一团糟。所以这是我的问题:
1) 我是否正确设置了并行进程?
2) 它是否继续尝试在 dedup_images()
上使用所有 8 个处理器?
3) 有什么我遗漏的 and/or 没有做对吗?
提前致谢!
EDIT 这就是我所说的 "haywire" 的意思。错误以这样的一堆行开始:
I/O Error: Couldn't open image If/iOl eE r'rSourb:p oICe/onOua l EdNrner'wot r Y:oo prCekon u Cliodmunan'gttey of1pi0e
l2ne1 1i'4mS auogbiepl o2fefinrlaee e N@'egSwmu abYipolor ekcn oaCm o Nupentwt y1Y -o18r16k11 8.C1po4nu gn3't4
y7 5160120821143 3p4t7I 9/49O-8 88E78r81r.3op rnp:gt ' C
3o-u3l6d0n.'ptn go'p
en image file 'Ia/ ON eEwr rYoorr:k CCIoo/uuOln dtEnyr' rt1o 0ro2:p1 e1Cn4o uiolmidalng2'eft r m '
ai gpceoo emfn iapl teN e1'w-S 8uY6bo2pr.okpe nnCgao' u
Nnetwy Y1o0r2k8 1C4o u3n4t7y9 918181881134 3p4t7 536-1306211.3p npgt'
4-879.png'
I/O Error: CoulId/nO' tE rorpoern: iCmoaugled nf'itl eo p'eub piomeangae fNielwe Y'oSrukb pCooeunnat yN e1w0 2Y8o1r
4k 3C4o7u9n9t8y8 811032 1p1t4 3o-i3l622f pt 1-863.png'
然后像这样多行变得更具可读性:
I/O Error: Couldn't open image file 'pt 1-864.png'
I/O Error: Couldn't open image file 'pt 1-865.png'
I/O Error: Couldn't open image file 'pt 1-866.png'
I/O Error: Couldn't open image file 'pt 1-867.png'
这会重复一段时间,在乱码错误文本和可读文本之间来回切换。
终于到了这里:
Deleting images smaller than 4KB and generating the MD5 hash values for all other images...
Extracting unique images into a new folder...
这意味着代码会恢复并继续该过程。可能出了什么问题?
- 是的,Pool.map接受一个带有 1 个参数的函数,然后是一个列表,其中的每个元素都作为参数传递给第一个函数。
- 不,因为除了
extract_images_from_file()
的正文,你在这里写的所有内容都在运行原始过程中。另外,我要指出您使用的是 8 个 进程 ,而不是 处理器 。如果您碰巧拥有 8 核英特尔 CPU,启用超线程,您将能够同时 运行 16 个进程。 - 我觉得不错,除了如果
extract_images_from_file()
抛出异常,它会破坏你的整个Pool
,这可能不是你想要的。为防止这种情况,您可以尝试绕过该块。
与您打交道的 "haywire" 的性质是什么?我们可以看到异常文本吗?
你的代码基本没问题。
乱码是所有试图将不同版本的 I/O Error
消息交错写入控制台的进程。错误消息是由 pdfimages
命令生成的,可能是因为当您 运行 两个同时发生冲突时,可能是因为临时文件,或者两者都使用相同的文件名或类似名称。
尝试为每个单独的 pdf 文件使用不同的图像根目录。