Python多进程代码仅能在终端/调试模式运行,求原因解释
Python多进程
if __name__ == '__main__':的作用及PyCharm运行报错解析 问题背景
我编写的Python多进程代码仅能通过终端执行或调试模式运行,在PyCharm普通运行模式(Shift+F10)下会出现EOFError和_pickle.PicklingError错误。教程反复强调if __name__ == '__main__':的重要性,但作为Python新手无法理解其中原因。
代码示例
import multiprocessing as mp def add_abc(a, b, c): print(a + b + c) def main(): # 创建数据列表 a = [1, 2, 3, 4, 5] b = [6, 7, 8, 9, 10] c = [11, 12, 13, 14, 15] processes = [] # 创建进程列表 for i in range(5): p = mp.Process(target=add_abc, args=(a[i], b[i], c[i])) processes.append(p) # 启动进程 for p in processes: p.start() # 等待进程结束 for p in processes: p.join() if __name__ == '__main__': main()
报错信息(部分)
File "D:\Program Files\Python311\Lib\multiprocessing\popen_spawn_win32.py", line 94, in __init__ reduction.dump(process_obj, to_child) File "D:\Program Files\Python311\Lib\multiprocessing\reduction.py", line 60, in dump ForkingPickler(file, protocol).dump(obj) _pickle.PicklingError: Can't pickle <function add_abc at 0x0000023408E3C540>: attribute lookup add_abc on __main__ failed Traceback (most recent call last): File "<string>", line 1, in <module> File "D:\Program Files\Python311\Lib\multiprocessing\spawn.py", line 120, in spawn_main exitcode = _main(fd, parent_sentinel) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\Program Files\Python311\Lib\multiprocessing\spawn.py", line 130, in _main self = reduction.pickle.load(from_parent) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EOFError: Ran out of input
预期正常输出
18 21 24 27 30
核心原因解释
1. 先搞懂__name__属性
Python里每个脚本/模块都有__name__属性:
- 当你直接运行脚本时,脚本的
__name__会被设置为'__main__' - 当脚本被作为模块导入到其他代码中时,
__name__会变成脚本的文件名(比如test.py对应的__name__是'test')
2. Windows多进程的启动逻辑
Windows没有Linux的fork机制,它采用spawn模式启动子进程:
- 启动子进程时,会重新启动一个Python解释器,完整执行一遍父进程的脚本(相当于把脚本当作模块import)
- 之后通过管道接收父进程传递的信息,定位到要执行的目标函数
3. if __name__ == '__main__':的必要性
如果不加这个判断,子进程执行脚本时会重复运行创建子进程的代码,导致无限递归创建进程,最终崩溃。
加上判断后,子进程执行脚本时__name__不是'__main__'(因为是被import的),所以不会执行main()里的进程创建逻辑,只会加载函数、类等定义。这样父进程才能通过pickle序列化把add_abc函数传递给子进程,子进程也能正确找到这个函数。
4. PyCharm不同运行模式的差异
- 普通运行模式:PyCharm通过一个包装器执行脚本,会改变脚本的
__name__属性或执行环境,导致子进程无法在__main__模块中找到add_abc函数,pickle序列化失败,进而抛出PicklingError和后续的EOFError - 终端/调试模式:终端直接执行脚本,
__name__正常设为'__main__';调试模式下PyCharm会调整执行环境,避免包装器的干扰,所以都能正常运行
总结
if __name__ == '__main__':是Windows下编写多进程代码的必要条件,它能阻止子进程重复执行进程创建逻辑,同时确保子进程能正确加载父进程传递的函数和对象。PyCharm普通运行的报错是其执行包装器干扰了脚本运行环境导致的,终端和调试模式则不存在这个问题。
内容的提问来源于stack exchange,提问作者Jiangpeng Li
相关产品推荐
相关产品推荐

