python - 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)
解决方案
您的代码有竞争条件。在最后一个数字被放入队列后,子进程在退出之前再休眠一次。这给了父进程足够的时间来获取该选项,休眠更短的时间,然后在等待第 11 个永远不会出现的项目之前得出结论,孩子仍然活着。
请注意,您ALIVE
在输出中获得的报告多于数字。这告诉你父进程在哪里死锁。
有几种可能的方法可以解决此问题。您可以foo
先将功能更改为睡眠,然后将项目放入队列中。这样它就可以在将 发送9
给其父级后立即停止运行,这可能会使其避免竞争条件(因为父级在收到每个项目后确实会休眠一小段时间)。如果事情表现得很奇怪,比赛发生的可能性仍然很小,但这不太可能。
更好的方法可能是完全防止比赛发生的可能性。例如,您可以将queue.get
调用更改为有一个集合,这样如果太长时间没有任何东西可以检索,timeout
它将放弃(有一个例外)。queue.Empty
您可以立即捕获该异常,甚至将其用作打破循环的计划方法,而不是测试孩子是否还活着,并在更高级别捕获它。
最后一个选项可能是从子节点向队列中的父节点发送一个特殊的哨兵值,以表明何时不会有更多的值到来。例如,您可以在函数结束None
之前将其作为最后一个值发送。foo
父代码可以检查该特定值并打破其循环,而不是将其视为正常值(例如打印它)。子代码完成的这种积极信号可能比超时的消极信号更好,因为出错(例如孩子崩溃)被误解为预期关闭的可能性较小。
推荐阅读
- r - R:将类型“列表”转换为数据框以转换为 excel - 文本挖掘
- android - 如何在 Kotlin 中将波斯/阿拉伯数字转换为英文数字?
- php - 如何在 MariaDB 中处理日历约会
- typescript - `tsc -b foo bar --watch` 只构建 foo,但不构建 bar
- python - 如何在 Python 中获取类的参数名称?
- javascript - RN声音电平开关静音-160到0
- javascript - 如何在使用 Elementor 构建的可变产品页面上将起始价格范围替换为实际变化价格?
- go - 标题已经写好了。想要用 500 覆盖状态码 200
- qt - 在 Yocto 中应用 .patch 文件不起作用
- javascript - 如何从外部 ip 访问我的 Vue 应用程序?