我正在尝试开始多处理,但遇到了一些有趣的问题。我使用的代码如下(为了记录在案,这个例子直接来自多处理文档(:
from multiprocessing import Process
def f(name):
print('hello', name)
if __name__ == '__main__':
p = Process(target=f, args=('bob'))
p.start()
p.join()
这很好用;你好鲍勃"正如它应该做的那样。但是,当我在if语句之前或之后向文件中添加任何额外的代码时,p不会求值,我的文件会循环回到开头,并无休止地重新运行。例如,下面的代码给出了这个问题:
from multiprocessing import Process
def f(name):
print('hello', name)
if __name__ == '__main__':
p = Process(target=f, args=('bob'))
p.start()
p.join()
test_input = input("test input")
我正在使用Windows 10、Pycharm v.2021.3.2和Python 3.10.0运行Python。这是你们以前见过的问题吗?在这一点上,我开始怀疑这是否是Windows和Pycharm或Windows和Python之间的问题,或者只是我缺乏经验的问题。
谢谢!
if __name__ == '__main__':
保护非常重要。在不使用fork
的系统上,它通过在每个工作进程中导入主脚本来模拟fork
,而不将其命名为__main__
(它的名称为__mp_main__
IIRC(。任何应该只在";主";脚本需要受到该保护(可以通过定义一个函数并在受保护的段内调用它来间接保护;该函数将在worker中定义,但不会运行(。
因此,要解决此问题,您所需要做的就是缩进test_input = input("test input")
,使其受到if __name__ == '__main__':
保护。在实际代码中,我试图保持保护部分的干净(这样我就不会意外地编写依赖全局状态的函数,而当它不作为主脚本运行时,全局状态是不存在的,并且为了使用函数局部值而不是全局值的轻微性能优势(,所以我会这样写:
from multiprocessing import Process
def f(name):
print('hello', name)
def main():
p = Process(target=f, args=('bob',))
p.start()
p.join()
test_input = input("test input")
if __name__ == '__main__':
main()
但这并不是绝对必要的。
我想我会详细说明ShadowRanger的答案:
在Windows系统上,通过以下步骤创建新的子流程:
- 创建了一个新进程,其中重新启动Python解释器
- Python解释器重新解释当前在全局范围内执行所有的源程序,以便编译函数定义、初始化全局变量等
- 最后,调用您的辅助函数,在本例中为
f
,并初始化内存
将创建子流程的代码放在由if __name__ == '__main__':
管理的块中的原因是,如果不这样做,那么由于上面的步骤2,您将进入一个递归的无限循环,创建新的子流程ad inifinity关键是只有在主函数中,变量__name__
才会具有值'__main__';对于所创建的任何子流程,它都将具有不同的值因此,创建新子流程(即p = Process(target=f, args=('bob',))
(的代码将不会作为子流程初始化的一部分执行。
您的问题源于语句test_input = input("test input")
位于全局范围,不在if __name__ == '__main__':
块内,因此它将作为子流程初始化的一部分执行。因此,在满足输入提示之前,您的辅助函数f
不会运行,然后当它返回时,您的主进程将再次发出提示。不管怎样,这就是我在Windows命令提示符下运行程序时看到的情况。也许PyCharm对从主线程以外的任何线程执行输入语句都有限制。但是,即使在创建子流程时从该语句中抛出异常,我仍然不太清楚您的程序将如何连续循环。不幸的是,我没有安装PyCharm。
关于ShadowRanger的答案,我认为你也应该在"bob"后面加逗号。根据https://docs.python.org/3/library/multiprocessing.html
如果你想放另一个语句,p应该是这样的。
p = Process(target=f, args=('bob',))