我想我在OpenCV的Python绑定中发现了一个错误,但由于主席和键盘之间总是存在机会问题而不是代码,我想在这里确认而不是立即提交一张票。 / p>
这是一个用于并行处理大量图像的简单脚本:
import cv2
import multiprocessing
import glob
import numpy
def job(path, output):
image = cv2.imread(path)
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
output.put(path)
if __name__ == "__main__":
main_image = cv2.imread("./image.png")
main_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
output = multiprocessing.Queue()
processes = []
for path in glob.glob("./data/*"):
process = multiprocessing.Process(
target=job,
args=(path, output))
process.start()
processes.append(process)
for process in processes:
process.join()
# Collect all results
results = [output.get() for process in processes]
print 'Finished'
在此代码results = [output.get() for process in processes]
中永远不会完成。
现在真正奇怪的是,如果我注释掉main_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
行,它对并行计算没有任何影响,那么脚本就完成了。
./image.png
和./data/
处的路径都会导致普通图像,总共约20个。
我尝试在内存中创建图像(numpy.ones([100, 100, 3]).astype(numpy.float32)
)并且没有产生错误。
我有类似的用C ++编写的代码,运行得很好。 我的环境:OS X 10.10,OpenCV 3.0.0,Python 2.7
所以,我是在做一些愚蠢的事情,还是这确实是OpenCV中出现并行计算的错误?
编辑: 我还尝试了使用multiprocessing.Pool.map()的实现,结果是一样的。这是代码
import cv2
import multiprocessing
import glob
import numpy
def job(path):
image = cv2.imread(path)
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
return path
if __name__ == "__main__":
image = cv2.imread("./image.png")
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
paths = glob.glob("./data/*")
pool = multiprocessing.Pool()
result = pool.map(job, paths)
print 'Finished'
for value in result:
print value
我能够使用非opencv任务获得正确的结果,所以我坚信问题出在opencv方面。但请随意证明我错了 - 我很乐意,因为这意味着我不必诉诸C ++。
答案 0 :(得分:1)
你get
之前不应该join
吗?
加入使用队列的进程
请记住,将项目放入队列的进程将等待 在终止之前,直到所有缓冲的项目都由 “馈线”螺纹到底层管道。 (子进程可以调用 队列的cancel_join_thread()方法可以避免这种行为。)
这意味着无论何时使用队列,您都需要确保这一点 所有已放入队列的项目最终都将被删除 在流程加入之前。否则你不能确定 将项目放入队列的进程将终止。记得 此外,非守护进程将自动加入。
将导致死锁的示例如下:
from multiprocessing import Process, Queue def f(q): q.put('X' * 1000000) if __name__ == '__main__': queue = Queue() p = Process(target=f, args=(queue,)) p.start() p.join() # this deadlocks obj = queue.get()
这里的修复方法是交换最后两行(或者只是删除p.join()行。)