【问题标题】:How to properly utilize the multiprocessing module in Python?如何正确利用 Python 中的多处理模块?
【发布时间】:2015-12-30 19:06:18
【问题描述】:

我正在尝试从中提取图像的 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)我有什么遗漏和/或做得不对吗?

提前致谢!

编辑这就是我所说的“乱码”。错误开始于一堆这样的行:

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...

这意味着代码会重新启动并继续该过程。可能出了什么问题?

【问题讨论】:

  • 对我来说这看起来不错。你能更具体地谈谈“失控”吗?
  • @strubbly 我已经在上面添加了错误输出。
  • “我已经开始涉足多线程。请随意解释为我说我不知道​​自己在做什么”你和其他开始使用并发工作的人。 >

标签: python multithreading parallel-processing multiprocessing


【解决方案1】:
  1. 是的,Pool.map 接受一个带有 1 个参数的函数,然后是一个列表,其中的每个元素都作为参数传递给第一个函数。
  2. 不,因为您在此处编写的所有内容都在原始进程中运行,extract_images_from_file() 的主体除外。另外,我要指出您使用的是 8 个进程,而不是处理器。如果您碰巧有一个 8 核 Intel CPU,并且启用了超线程,您将能够同时运行 16 个进程。
  3. 对我来说看起来不错,只是如果extract_images_from_file() 抛出异常,它会破坏你的整个Pool,这可能不是你想要的。为防止这种情况,您可以尝试绕过该块。

您正在处理的“失控”的性质是什么?我们可以看到异常文本吗?

【讨论】:

    【解决方案2】:

    你的代码基本没问题。

    乱码文本是所有试图写入不同版本的I/O Error 消息的进程交错到控制台。错误消息是由pdfimages 命令生成的,可能是因为当您同时运行两个时,它们会发生冲突,可能是临时文件,或者两者都使用相同的文件名或类似名称。

    尝试为每个单独的 pdf 文件使用不同的图像根。

    【讨论】:

    • 我接受了这个作为答案,因为它有效地解决了我遇到的问题。我在根名称后附加了一个随机的 3 位字母数字代码,它完全缓解了任何问题。谢谢!
    • 酷 - 你在多处理方面做得很好 - 请记住,你调用的东西需要能够一起运行。当它们共享目录或文件等资源时,它们可能会发生冲突。
    猜你喜欢
    • 2016-03-19
    • 1970-01-01
    • 1970-01-01
    • 2021-07-31
    • 2014-12-05
    • 2013-12-21
    • 2011-04-04
    • 2017-12-11
    • 1970-01-01
    相关资源
    最近更新 更多