我有一个问题需要了解python 3中multiprocessing
模块中的队列
这就是他们在programming guidelines中所说的:
请记住,将项目放入队列的进程将等待 终止,直到所有缓冲的项目由“馈线”线程馈送到 底层管道。 (子进程可以调用 Queue.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()line)。
显然,queue.get()
之后不应调用join()
。
但是,有一些使用队列的示例get
之后调用join
:
import multiprocessing as mp
import random
import string
# define a example function
def rand_string(length, output):
""" Generates a random string of numbers, lower- and uppercase chars. """
rand_str = ''.join(random.choice(
string.ascii_lowercase
+ string.ascii_uppercase
+ string.digits)
for i in range(length))
output.put(rand_str)
if __name__ == "__main__":
# Define an output queue
output = mp.Queue()
# Setup a list of processes that we want to run
processes = [mp.Process(target=rand_string, args=(5, output))
for x in range(2)]
# Run processes
for p in processes:
p.start()
# Exit the completed processes
for p in processes:
p.join()
# Get process results from the output queue
results = [output.get() for p in processes]
print(results)
我已运行此程序并且可以正常运行(也作为StackOverFlow问题Python 3 - Multiprocessing - Queue.get() does not respond的解决方案发布)。
有人可以帮我理解僵局的规则是什么吗?
答案 0 :(得分:31)
允许在进程之间传输数据的多处理中的队列实现依赖于标准的OS管道。
操作系统管道不是无限长,因此在put()
操作期间可以在操作系统中阻止对数据进行排队的进程,直到某个其他进程使用get()
从队列中检索数据。
对于少量数据,例如示例中的数据,主进程可join()
生成所有子进程,然后获取数据。这通常很有效,但不能扩展,并且不清楚何时会破坏。
但它肯定会打破大量数据。子进程将在put()
中被阻止,等待主进程使用get()
从队列中删除一些数据,但主进程在join()
中被阻止,等待子进程完成。这会导致死锁。
以下是用户this exact issue的示例。我在答案中发布了一些代码,帮助他解决了问题。
答案 1 :(得分:0)
在从共享队列中获取所有消息之前,不要在进程对象上调用join()
。
我使用以下解决方法允许进程在处理其所有结果之前退出:
results = []
while True:
try:
result = resultQueue.get(False, 0.01)
results.append(result)
except queue.Empty:
pass
allExited = True
for t in processes:
if t.exitcode is None:
allExited = False
break
if allExited & resultQueue.empty():
break
它可以缩短,但我把它留了更长时间以便新手更清楚。
此处resultQueue
是与multiprocess.Queue
个对象共享的multiprocess.Process
。在这段代码之后,您将获得包含队列中所有消息的result
数组。
问题是接收消息的队列管道的输入缓冲区可能会变满,导致写入程序无限阻塞,直到有足够的空间来接收下一条消息。所以你有三种方法可以避免阻塞:
multiprocessing.connection.BUFFER
尺寸(不太好)