为什么生成的进程没有启动



我在使用Python的多处理模块时遇到问题。这里是一个(非常)简化版本的问题,我试图使用一个多处理队列来产生的进程和主进程之间的通信:

from time import sleep
import multiprocessing as mp
# add number to queue Q every 2 second, then None
def func(Q):
for i in range(1,11):  
Q.put(i)
sleep(2)
Q.put(None)
# start the process to add numbers
Q = mp.Queue()
P = mp.Process(target=func, args=(Q,))
P.start()
# place some initial values in the queue
for n in range(10,15):
sleep(0.5)
Q.put(n)
# wait a bit to let process start
print("waiting...")
sleep(2)
# get everything from the queue up to None
while True:
n = Q.get()
if n is None: break
print(n)

进程(func)应该向队列中添加项目,但它没有启动或莫名其妙地卡住了。

我得到的输出是:
waiting...
10
11
12
13
14

我希望1到10出现在那里的某个地方,循环最终结束(但它没有)

我错过了什么?

顺便说一下,我是在MacOS Monterey(12.6)上用Python 3.7做的。Macbook Pro (2.9 GHz 6核Intel Core i9)

我还尝试了一堆更简单的多处理的例子从网络上,他们似乎都没有工作(但他们中的大多数试图从子进程打印,这不是我想要/需要处理的问题)。

我终于想通了。MacOS只有"spawn";作为Python 3.8的默认启动方法(所以我的假设是错误的)。此外,我应该在我的过度简化的例子中使用if __name__ == '__main__':条件,因为spawn实际上启动了一个新的解释器,并递归地执行进程创建代码。在11..队列中的14个数字更清楚地表明这足以使它工作(我最初认为p .join()是罪魁祸首)。

下面是我的简化示例的代码:

from time import sleep
import multiprocessing as mp
def func(Q):
for i in range(1,11):  
Q.put(i)
sleep(1)
Q.put(None)

if __name__ == "__main__":
mp.set_start_method("spawn")

# start the process to add numbers
Q = mp.Queue()
P = mp.Process(target=func, name="child", args=(Q,),daemon=True)
P.start()    
# place some initial values in the queue
for n in range(10,15):
sleep(0.5)
Q.put(n)
# wait a bit to let process start
print("waiting...")
sleep(2)
# get everything from the queue up to None
while True:
n = Q.get()
if n is None: break
print(n)

运行代码,我得到一个大大的红色警告,上面写着

RuntimeError:已经尝试在…之前开始一个新的进程当前进程已完成启动阶段。

这可能意味着您没有使用fork来启动您的子进程和您忘记使用适当的习语在主模块中:

if __name__ == '__main__':
freeze_support()
...

"freeze_support()";行可以省略,如果程序不会被冻结以生成可执行文件

一旦我按照指令执行,你的代码就可以正常工作了。

我也做了一些重构来遵循一些PEP的建议,只是因为我可以。

from time import sleep
import multiprocessing as mp

def produce(queue: mp.Queue) -> None:
for i in range(1, 11):
queue.put(i)
sleep(2)
queue.put(None)

def consume(queue: mp.Queue) -> None:
while True:
n = queue.get()
if n is None:
break
print(n)

if __name__ == '__main__':
dataexchange = mp.Queue()
for number in range(10, 15):
dataexchange.put(number)
process = mp.Process(target=produce, args=(dataexchange,))
process.start()
print("waiting...")
sleep(2)
consume(dataexchange)

当使用"spawn"作为启动方法),因此子进程将引发RuntimeError。问题是这个异常是从子进程生成的,所以主进程将继续等待已经退出的子进程的响应。没有正确重定向STDERR的IDE可能不会打印错误消息,因此您应该通过Terminal运行代码,以确保您看到错误(并像Thomas所做的那样纠正它)。

相关内容

  • 没有找到相关文章

最新更新