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

PyTesseract call working very slow when used along with multiprocessing

我有一个函数,它接收图像列表并在对图像应用 OCR 后在列表中生成输出。我有另一个函数通过使用多处理来控制此函数的输入。因此,当我有一个列表(即没有多处理)时,列表中的每个图像花费了大约 1 秒,但是当我将必须并行处理的列表增加到 4 个时,每个图像花费了惊人的 13 秒。

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

我的目标是 运行 eat100 没有多处理, eat25 有多处理(有 4 个进程)。从理论上讲,如果我有 4 个独立的处理器(我有 2 个内核,每个内核有 2 个线程,因此 CPU(s) = 4(如果我'我在这里错了))。

但是当我看到代码在打印 "Processing 0" 4 次后甚至没有响应时,所有的理论都付诸东流了。不过,单处理器功能 eat100 工作正常。

我已经测试了一个简单的范围立方体函数,它在多处理下工作得很好,所以我的处理器肯定工作得很好。这里唯一的罪魁祸首可能是:

`

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。如果人们重现代码并检查问题是否仍然存在,我会很高兴。

我是pathos作者。如果您的代码连续使用 1s 到 运行,那么很可能在天真的并行过程中需要更长的时间才能达到 运行。使用天真的进程并行会产生开销:

  1. 必须在每个处理器上启动一个新的 python 实例
  2. 您的函数和依赖项需要序列化并发送到每个处理器
  3. 您的数据需要序列化并发送给处理器
  4. 反序列化相同
  5. 您可以 运行 从长期池或大量数据序列化中解决内存问题。

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

  • 尝试 pathos.pools.ThreadPool 使用线程并行而不是进程并行。这可以减少序列化和启动池的一些开销。
  • 尝试 pathos.pools._ProcessPool 更改 pathos 管理池的方式。如果没有下划线,pathos 将池保持为单例,并且需要 'terminate' 来显式终止池。带有下划线的是,当您删除池对象时,池将消失。请注意,您的 caller 函数不会 closejoin(或 terminate)池。
  • 您可能想通过尝试 dill.dumps 您尝试并行处理的元素之一来检查您正在序列化多少。像大 numpy 数组这样的东西可能需要一段时间才能序列化。如果传递的内容很大,您可以考虑使用共享内存数组(即 multiprocess.Arraynumpy 数组的等效版本——另请参阅:numpy.ctypeslib)最小化每个进程之间传递的内容。

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