Python多处理 - 产生的进程终止时主进程不会继续

Posted

技术标签:

【中文标题】Python多处理 - 产生的进程终止时主进程不会继续【英文标题】:Python multiprocessing - main process wont continue when spawned process terminated 【发布时间】:2021-07-17 12:03:59 【问题描述】:

我想在一个新进程中在 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

在某些时候,“Alive”和“Process finished”都不会被打印出来。生成的进程停止运行时如何继续执行?

*编辑

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

【问题讨论】:

【参考方案1】:

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

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

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

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

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

【讨论】:

所以 Queue.get() 阻塞直到下一个项目被放入队列?我不知道。我正在尝试使用 Queue.get(block=False) 修复它,非常感谢! 这是默认设置,是的。使用block=False,它根本不会阻塞。使用block=True(这是默认值),您可以指定timeout,这将在指定时间后解除阻塞(并引发我提到的异常)。查看the docs。

以上是关于Python多处理 - 产生的进程终止时主进程不会继续的主要内容,如果未能解决你的问题,请参考以下文章

为啥不能从 Kivy 终止这个 Python 多处理进程?

Python多处理池:完成任何k个作业后终止进程

Python多处理:超过超时后通过参数终止进程

如何终止多处理池进程?

你如何让多处理池不启动新进程但也不终止当前正在运行的进程?

exit-code影响配置文件吗