与多处理一起使用时,PyTesseract调用工作非常缓慢

时间:2018-11-25 14:23:54

标签: python multiprocessing tesseract pathos python-tesseract

我有一个函数,可以在将OCR应用于图像之后,获取图像列表并在列表中生成输出。我还有另一个功能,可以使用多重处理来控制该功能的输入。因此,当我只有一个列表(即没有多处理)时,列表中的每个图像大约要花1s,但是当我将必须并行处理的列表增加到4时,每个图像则要花13s的惊人时间。

要了解问题的根源,我尝试创建一个最小的问题工作示例。在这里,我有两个函数eat25eat100,它们打开一个图像name并将其提供给使用API​​ pytesseract的OCR。 eat25做25次,eat100做100次。

我的目的是在不进行多处理的情况下运行eat100,而在进行多处理(具有4个进程)的情况下运行eat25。从理论上讲,如果我有4个单独的处理器(我有2个内核,每个内核有2个线程,因此CPU = 4(如果我错了,请更正我)),时间应该比eat100少4倍)。

但是,当我看到代码在打印4次“正在处理0”后甚至没有响应时,所有的理论都浪费了。单处理器功能eat100可以正常工作。

我已经测试了一个简单的范围求值功能,并且在多处理中效果很好,所以我的处理器肯定可以正常工作。唯一的罪魁祸首可能是:

  • pytesseract:请参见this
  • 错误代码?我做错了什么。

`

from pathos.multiprocessing import ProcessingPool
from time import time 
from PIL import Image
import pytesseract as pt
def eat25(name):
    for i in range(25):
        print('Processing :'+str(i))
        pt.image_to_string(Image.open(name),lang='hin+eng',config='--psm 6')
def eat100(name):
    for i in range(100):
        print('Processing :'+str(i))
        pt.image_to_string(Image.open(name),lang='hin+eng',config='--psm 6')
st = time()
eat100('normalBox.tiff')
en = time()
print('Direct :'+str(en-st))
#Using pathos
def caller():
    pool = ProcessingPool()
    pool.map(eat25,['normalBox.tiff','normalBox.tiff','normalBox.tiff','normalBox.tiff'])
if (__name__=='__main__'):
    caller()
en2 = time()

print('Pathos :'+str(en2-en))

那么,问题出在哪里呢?任何帮助表示赞赏!

编辑: 图像normalBox.tiff可以找到here。如果人们能重现代码并检查问题是否仍然存在,我将感到很高兴。

1 个答案:

答案 0 :(得分:2)

我是pathos作者。如果您的代码需要1s来串行运行,那么很可能在幼稚的进程中并行运行会花费更长的时间。处理朴素的进程并行会产生开销:

  1. 必须在每个处理器上旋转一个新的python实例
  2. 您的函数和依赖项需要序列化并发送到每个处理器
  3. 您的数据需要进行序列化并发送到处理器
  4. 反序列化相同
  5. 您可能会遇到长寿命池或大量数据序列化中的内存问题。

我建议您检查一些简单的方法来检查您的问题可能在哪里:

  • 尝试pathos.pools.ThreadPool使用线程并行而不是进程并行。这样可以减少序列化和扩展池的一些开销。
  • 尝试pathos.pools._ProcessPool更改pathos管理池的方式。如果没有下划线,pathos会将池保持为单例状态,并且需要使用“终止符”来明确终止池。如果使用下划线,则删除池对象时池将死亡。请注意,您的caller函数不是closejoin(或terminate)池。
  • 您可能想通过尝试dill.dumps尝试并行处理的元素之一来检查要序列化的数量。大型numpy阵列之类的内容可能需要一段时间才能序列化。如果要传递的内容很大,则可以考虑使用共享内存数组(即multiprocess.Arraynumpy数组的等效版本-另请参见:numpy.ctypeslib)尽量减少每个流程之间传递的内容。

后者需要更多工作,但是如果您有很多需要序列化的内容,则可以节省大量资金。没有共享的内存池,因此,如果需要走那条路由,则必须对单个multiprocess.Process对象进行for循环。