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 崩溃)被误解为预期的关闭.
我想在新进程中 运行 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 崩溃)被误解为预期的关闭.