Python multiprocessing - 生成进程终止时主进程不会继续

Python multiprocessing - main process wont continue when spawned process terminated

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

我得到以下代码,运行新进程中的函数 foo 和使用队列的 returns 进度:

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

有时既不会打印“Alive”也不会打印“Process finished”。当生成的进程停止 运行ning 时如何继续执行?

*编辑

问题是我不知道如果队列为空,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)

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

请注意,与数字相比,您在输出中获得的 ALIVE 报告更多。这告诉您 parent 进程在哪里死锁。

有几种可能的方法可以解决此问题。您可以将 foo 函数更改为先休眠,然后再将项目放入队列中。这将使它可以在将 9 发送到它的 parent 后立即退出 运行,这可能会允许它避免竞争条件(因为 parent 确实在收到每件物品后会睡一小会儿)。如果事情表现得非常奇怪,仍然有很小的可能会发生比赛,但这种可能性很小。

更好的方法可能是完全防止发生竞争的可能性。例如,您可以将 queue.get 调用更改为设置 timeout,这样如果太长时间没有可检索的内容,它将放弃(出现 queue.Empty 异常)。您可以立即捕获该异常,甚至可以将其用作打破循环的计划方法,而不是测试 child 是否仍然存在,然后在更高级别捕获它。

最后一个选项可能是将一个特殊的标记值从 child 发送到队列中的 parent,以在没有其他值到来时发出信号。例如,您可以发送 None 作为最后一个值,就在 foo 函数结束之前。 parent 代码可以检查该特定值并在其循环时中断,而不是将其视为正常值(例如打印它)。这种 child 代码完成的积极信号可能比超时的消极信号更好,因为它不太可能出现问题(例如 child 崩溃)被误解为预期的关闭.