我有一个使用subprocess
模块的Popen
运行的进程:
result = subprocess.Popen(['tesseract','mypic.png','myop'])
st = time()
while result.poll() is None:
sleep(0.001)
en = time()
print('Took :'+str(en-st))
这将导致:
Took :0.44703030586242676
在这里,进行tesseract
调用以处理图像mypic.png
(已附加)并将OCR的结果输出到myop.txt
。
现在,我希望这代表this comment(或参见this directly)在多个进程上发生,所以代码在这里:
lst = []
for i in range(4):
lst.append(subprocess.Popen(['tesseract','mypic.png','myop'+str(i)]))
i=0
l = len(lst)
val = 0
while(val!=(1<<l)-1):
if(lst[i].poll() is None):
print('Waiting for :'+str(i))
sleep(0.01)
else:
temp = val
val = val or (1<<(i))
if(val!=temp):
print('Completed for :'+temp)
i = (i+1) %l
此代码的作用是对tesseract
进行4次调用,将过程对象保存在列表lst
中,对所有这些对象进行迭代,直到完成所有所有 。底部给出了无限循环实现的说明。
这里的问题是后一个程序要花费大量时间才能完成。它使用poll()
函数None
持续等待过程完成,直到过程尚未完成。这本不应该发生的。它应该只花了0.44s多一点的时间。大概不到10分钟!为什么会这样?
我通过深入研究pytesseract
来解决此特定错误,当使用multiprocessing
或pathos
并行运行时,这花费了很多时间。因此,这是一个更大版本的缩小版本。我对此有疑问,here。
无限循环的解释:
val
最初为0。当第i个过程完成时,它与2^i
进行或运算。因此,如果有3个进程,则如果第一个进程(i = 0)完成,则2^0 = 1
与val
进行或运算为1。第二个和第三个进程完成后,{{ 1}}变成val
| 2^0
| 2^1
= 7。2^2
也是7。因此,循环一直进行到2^3-1
等于val
。
答案 0 :(得分:1)
每the faq(我强调):
Tesseract 4在处理一个页面时还使用多达四个CPU线程,因此单个页面的速度将比Tesseract 3快。
如果您的计算机只有两个CPU内核,那么运行四个线程会大大减慢速度,因此最好使用单个线程或最多两个线程! 使用单线程消除了多线程的计算开销,并且通过在每个CPU内核上运行一个Tesseract进程,也是处理大量图像的最佳解决方案。。
使用环境变量OMP_THREAD_LIMIT设置最大线程数。
要禁用多线程,请使用OMP_THREAD_LIMIT = 1。
因此,如果您希望同时运行多个tesseract进程,则可能希望减少(或试验)OMP_THREAD_LIMIT。 最佳值取决于您的计算机可以同时支持多少个线程。
例如,在我的机器上:
import subprocess
import time
import os
t = time.perf_counter()
tasks = [('mypic.png', 'myop{}'.format(i)) for i in range(4)]
procs = [subprocess.Popen(['tesseract', infile, outfile], env={'OMP_THREAD_LIMIT':'1'})
for infile, outfile in tasks]
for proc in procs:
proc.wait()
print('{} s'.format(time.perf_counter()-t))
在0.220秒内完成,而没有env={'OMP_THREAD_LIMIT':'1'}
的相同代码
通常需要3.1到5.1秒之间的时间,每次跑步之间会有很多差异。
要使代码正常工作,请使用binary bitwise or operator, |
而不是logical or operator, or
:
val = val | (1 << (i))
例如,
import time
import subprocess
lst = []
for i in range(4):
lst.append(subprocess.Popen(['tesseract', 'mypic.png', 'myop'+str(i)]))
i = 0
l = len(lst)
val = 0
counter = 0
while(val != (1 << l)-1):
if(lst[i].poll() is None):
time.sleep(0.001)
else:
temp = val
val = val | (1 << (i))
if(val != temp):
print('Completed for : {}'.format(i))
i = (i+1) % l
counter += 1
print('{} iterations'.format(counter))
打印输出类似
Completed for : 1
Completed for : 2
Completed for : 3
Completed for : 0
6121 iterations
请注意,循环仍会迭代数千次,主要是在lst[i].poll()
返回None
的时候,
也是因为i = (i+1) % l
可以多次访问相同的值。
如果一次迭代花费0.001s,那么6121次迭代将花费6.121s。因此while
循环很复杂,而且速度不是很快。