为什么多处理中的get()在Python中花费了这么多时间?
我正在尝试使用Python中的多重处理在树莓Pi上进行人脸识别。为了充分利用所有4个内核,我使用了多线程的概念。下面是我的(伪)代码的一部分: 据我所知,与实际图像捕获(三个周期)相比,显示图像会有一些延迟。我不明白的是,运行这个算法会有一定程度的卡住现象。可能是这样的:为什么多处理中的get()在Python中花费了这么多时间?,python,multithreading,face-recognition,Python,Multithreading,Face Recognition,我正在尝试使用Python中的多重处理在树莓Pi上进行人脸识别。为了充分利用所有4个内核,我使用了多线程的概念。下面是我的(伪)代码的一部分: 据我所知,与实际图像捕获(三个周期)相比,显示图像会有一些延迟。我不明白的是,运行这个算法会有一定程度的卡住现象。可能是这样的: 平滑显示r1、r2、r3、r4的结果,然后卡住1s,然后平滑显示r1-r4和 或 平滑显示r2、r3、r4、r1的结果,然后卡住1s,然后平滑显示r2-r1和 它可以是从r1、r2、r3、r4开始的任何序列。我不明白是什么原因
下面是一个简单的示例,解释了您看到的模式 假设你有4个人,面前有4杯空的水。把get()想象成“喝完你杯子里的水,我会等你喝完再继续”。把apply_async想象成“我要把你的杯子装满,开始喝酒,但我要继续” 那么会发生什么:
count == 1
We fill person A's glass and they're drinking slowly
We wait for person B to finish their cup, it's already empty, we move on
count == 2
We fill person B's glass and they're drinking slowly
We wait for person C to finish their cup, it's already empty, we move on
...
count == 4
We fill person D's glass and they're drinking slowly
We wait for person A to finish their cup
好的,假设A需要30秒来完成他们的水,但是我们只需要5秒来完成上面的步骤
我们现在要等25秒,等A喝完他们的酒,然后再继续。但是由于等待的时间很长,B、C和D三个人也喝完了酒,所以A喝完后,我们放大接下来的三个人,直到我们再次回到A。这里有一个简单的例子解释了你看到的模式 假设你有4个人,面前有4杯空的水。把get()想象成“喝完你杯子里的水,我会等你喝完再继续”。把apply_async想象成“我要把你的杯子装满,开始喝酒,但我要继续” 那么会发生什么:
count == 1
We fill person A's glass and they're drinking slowly
We wait for person B to finish their cup, it's already empty, we move on
count == 2
We fill person B's glass and they're drinking slowly
We wait for person C to finish their cup, it's already empty, we move on
...
count == 4
We fill person D's glass and they're drinking slowly
We wait for person A to finish their cup
好的,假设A需要30秒来完成他们的水,但是我们只需要5秒来完成上面的步骤
我们现在要等25秒,等A喝完他们的酒,然后再继续。但是由于等待的时间很长,B、C和D三个人也喝完了酒,所以一旦A喝完,我们就放大接下来的三个人,直到我们再次回到A。如果你真的想尽快解雇这些工作,并在他们有空的情况下尽快获得结果,而不阻止解雇新的工作,你必须停止交错它们 最简单的方法(假设您希望按照任务创建的顺序获得结果1)可能是在后台线程上等待,如下所示:
q = queue.Queue()
def handle():
while True:
res = q.get()
output = res.get()
showimage(output)
threading.Thread(target=handle)
while True:
image = cap.read
res = pool.apply_async(func, [image])
q.put(res)
这种精确的设计可能不起作用,例如,如果showimage
必须在主线程上运行,则必须交换两个线程,如果cap.read
也必须在主线程上运行,则需要管理多个队列,并使一切更加复杂,但这应该说明了这一点
一,。如果您希望结果以任何顺序完成,那么从
多处理.Pool
切换到并发.futures.ProcessPoolExecutor
可能会更简单,因为等待一组future
比等待一组AsyncResult
更容易。但是还有其他选择。如果你真的想尽快解雇这些工作,并在结果可用时立即获取结果,而不阻止解雇的新工作,你必须停止交错
最简单的方法(假设您希望按照任务创建的顺序获得结果1)可能是在后台线程上等待,如下所示:
q = queue.Queue()
def handle():
while True:
res = q.get()
output = res.get()
showimage(output)
threading.Thread(target=handle)
while True:
image = cap.read
res = pool.apply_async(func, [image])
q.put(res)
这种精确的设计可能不起作用,例如,如果showimage
必须在主线程上运行,则必须交换两个线程,如果cap.read
也必须在主线程上运行,则需要管理多个队列,并使一切更加复杂,但这应该说明了这一点
一,。如果您希望结果以任何顺序完成,那么从
多处理.Pool
切换到并发.futures.ProcessPoolExecutor
可能会更简单,因为等待一组future
比等待一组AsyncResult
更容易。但是还有其他选择。如果处理器还没有完成图像处理,它会在get()调用中被阻塞吗?也许我不明白你的问题,我觉得这就是问题所在,但我不知道根本原因是什么。让我为您的分析提供一些分析结果的快照。哦,对了,我想我终于理解了您的问题描述。是的,get()调用会阻止您,但其他处理器仍在加载它们的值,因此每4次调用您都会被卡住。这可能需要一段时间才能完成。在启动每个任务n
之后,您需要明确地等待任务n-3
完成,然后再执行其他操作。如果您不想等待,而是想尽快启动任务,并在任务进入时处理它们,那么您需要更改它,以便在任务进入时等待,而不是与生成任务交织在一起。例如,您可以将每个AsyncResult
粘贴到queue.queue
上,并使用一个后台线程循环res=q.pop();输出=res.get();showimage(output)
(或者,如果您不想让它们按顺序排列,您可以使用并发.futures.ProcessPoolExecutor中的future
s,而不是多处理.Pool中的AsyncResult
)如果处理器尚未完成图像处理,它将被卡在那里