首页 > 解决方案 > Python多处理 - 产生的进程终止时主进程不会继续

问题描述

我想在一个新进程中在 python 中运行一个函数,做一些工作,使用队列将进度返回到主进程并等待主进程终止生成的进程,然后继续执行主进程。

我得到以下代码,它在新进程中运行函数 foo 并使用队列返回进度:

import multiprocessing as mp
import time

def foo(queue):
    for i in range(10):
        queue.put(i)
        time.sleep(1)

if __name__ == '__main__':
    mp.set_start_method('spawn')
    queue = mp.Queue()
    p = mp.Process(target=foo, args=(queue,))
    p.start()
    while p.is_alive():
        print("ALIVE")
        print(queue.get())
        time.sleep(0.01)
    print("Process finished")

输出是:

ALIVE
0
ALIVE
1
ALIVE
2
ALIVE
3
ALIVE
4
ALIVE
5
ALIVE
6
ALIVE
7
ALIVE
8
ALIVE
9
ALIVE

在某些时候,既不会打印“活着”,也不会打印“处理完成”。当生成的进程停止运行时,如何继续执行?

*编辑

问题是如果队列为空,我不知道 queue.get() 会阻塞,直到将一个项目放入队列中。我通过改变来修复它

while p.is_alive():
    print(queue.get())
    time.sleep(0.01)

while p.is_alive():
    if not queue.empty():
        print(queue.get())
    time.sleep(0.01)

标签: pythonpython-3.xmultiprocessingpython-multithreading

解决方案


您的代码有竞争条件。在最后一个数字被放入队列后,子进程在退出之前再休眠一次。这给了父进程足够的时间来获取该选项,休眠更短的时间,然后在等待第 11 个永远不会出现的项目之前得出结论,孩子仍然活着。

请注意,您ALIVE在输出中获得的报告多于数字。这告诉你父进程在哪里死锁。

有几种可能的方法可以解决此问题。您可以foo先将功能更改为睡眠,然后将项目放入队列中。这样它就可以在将 发送9给其父级后立即停止运行,这可能会使其避免竞争条件(因为父级在收到每个项目后确实会休眠一小段时间)。如果事情表现得很奇怪,比赛发生的可能性仍然很小,但这不太可能。

更好的方法可能是完全防止比赛发生的可能性。例如,您可以将queue.get调用更改为有一个集合,这样如果太长时间没有任何东西可以检索,timeout它将放弃(有一个例外)。queue.Empty您可以立即捕获该异常,甚至将其用作打破循环的计划方法,而不是测试孩子是否还活着,并在更高级别捕获它。

最后一个选项可能是从子节点向队列中的父节点发送一个特殊的哨兵值,以表明何时不会有更多的值到来。例如,您可以在函数结束None之前将其作为最后一个值发送。foo父代码可以检查该特定值并打破其循环,而不是将其视为正常值(例如打印它)。子代码完成的这种积极信号可能比超时的消极信号更好,因为出错(例如孩子崩溃)被误解为预期关闭的可能性较小。


推荐阅读