与多处理一起使用时,PyTesseract 调用工作非常缓慢
Posted
技术标签:
【中文标题】与多处理一起使用时,PyTesseract 调用工作非常缓慢【英文标题】:PyTesseract call working very slow when used along with multiprocessing 【发布时间】:2019-04-27 08:24:42 【问题描述】:我有一个函数,它接收图像列表并在将 OCR 应用于图像后在列表中生成输出。我有另一个函数通过使用多处理来控制该函数的输入。因此,当我有一个列表(即没有多重处理)时,列表中的每个图像花费了大约 1 秒,但是当我将必须并行处理的列表增加到 4 个时,每个图像花费了惊人的 13 秒。
为了了解问题的真正所在,我尝试创建一个最小的问题工作示例。在这里,我有两个函数eat25
和eat100
,它们打开图像name
并将其提供给使用API pytesseract
的OCR。 eat25
执行 25 次,eat100
执行 100 次。
我的目标是在没有多处理的情况下运行 eat100
,并在多处理的情况下运行 eat25
(有 4 个进程)。从理论上讲,如果我有 4 个独立的处理器(我有 2 个内核,每个内核有 2 个线程,因此 CPU(s) = 4(如果我在这里错了,请纠正我),这应该比 eat100
少 4 倍的时间。
但是当我看到代码在打印“处理 0”4 次后甚至没有响应时,所有理论都被浪费了。单处理器函数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。如果人们重现代码并检查问题是否仍然存在,我会很高兴。
【问题讨论】:
我注意到您正在使用pathos.multiprocessing
模块。为什么不使用标准 concurrent.futures 包中的原生 ProcessPoolExecutor
?
【参考方案1】:
我是pathos
作者。如果您的代码需要1s
串行运行,那么在幼稚的并行进程中运行很可能需要更长的时间。使用幼稚的并行处理会产生开销:
-
必须在每个处理器上启动一个新的 python 实例
您的函数和依赖项需要序列化并发送到每个处理器
您的数据需要序列化并发送到处理器
反序列化也是如此
您可能会遇到来自长寿命池或大量数据序列化的内存问题。
我建议检查一些简单的事情来检查您的问题可能出在哪里:
尝试pathos.pools.ThreadPool
使用线程并行而不是进程并行。这可以减少序列化和启动池的一些开销。
尝试pathos.pools._ProcessPool
更改pathos
管理池的方式。如果没有下划线,pathos
将池保持为单例,并且需要“终止”来明确终止池。使用下划线,当您删除池对象时,该池将终止。请注意,您的 caller
函数不会 close
或 join
(或 terminate
)池。
您可能希望通过尝试dill.dumps
您尝试并行处理的元素之一来检查您的序列化程度。像大numpy
数组这样的东西可能需要一段时间才能序列化。如果传递的内容很大,您可以考虑使用共享内存数组(即multiprocess.Array
或numpy
数组的等效版本——另请参阅:numpy.ctypeslib
)以最小化传递的内容每个进程之间。
后者的工作量更大,但如果您有很多要序列化的内容,可以节省大量资金。没有共享内存池,所以如果你需要走这条路,你必须对单个 multiprocess.Process
对象进行 for 循环。
【讨论】:
感谢您的回答!我只是想告诉你,这段代码在 Windows 中运行良好非常。这是真正的问题。 另外,关于您的建议,前两个的行为方式与原来的相同。dill
中的tiff
图像存在问题,因为在酸洗和解酸之后,tiff 图像在馈送到pytesseract
时会引发错误。与 PNG 一起使用时效果很好。
我也是dill
的作者。 dill
对tiff
图像与png
图像一无所知...所以很可能是某些对象(我假设)pytesseract
创建以处理tiff
的问题。首先,让我看看我是否理解正确......代码在 Windows 上的行为与预期一样,但在 linux/mac 上挂起?其次,您可以在尝试发送给不同并行工作人员的对象上尝试dill.copy
和dill.check
吗?如果两者或其中任何一个都抛出错误,那么你有一个序列化问题。然后,您可以使用dill.detect.trace
诊断任何序列化问题。
是的,它在 linux 上挂起(准确地说,工作非常缓慢)。虽然没有在 mac 上测试过。
您正在将名称(string
)映射到pytesseract.image_to_string
的返回值。所以序列化应该只需要处理返回的任何对象(看起来可能是一个字符串)。所以,我怀疑这是导致问题的原因。如果您只是将字符串传入和传出进程......那么最有可能的候选者是内存问题。你在交换你的记忆吗?以上是关于与多处理一起使用时,PyTesseract 调用工作非常缓慢的主要内容,如果未能解决你的问题,请参考以下文章