You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 04:57:04