python多进程报错的解决方案

在运行多进程下载数据时,程序报错,

RuntimeError: An attempt has been made to start a new process before the
current process has finished its bootstrapping phase.

This probably means that you are not using fork to start your
child processes and you have forgotten to use the proper idiom
in the main module:

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

The "freeze_support()" line can be omitted if the program
is not going to be frozen to produce an executable.


  File "C:\Users\admin\AppData\Local\Programs\Python\Python38\lib\concurrent\futures\_base.py", line 437, in result
    return self.__get_result()
  File "C:\Users\admin\AppData\Local\Programs\Python\Python38\lib\concurrent\futures\_base.py", line 389, in __get_result
    raise self._exception
concurrent.futures.process.BrokenProcessPool: A process in the process pool was terminated abruptly while the future was running or pending.

解决方案

这个报错的原因是因为:程序尝试在Python的多进程环境中启动一个新进程,但是在当前进程完成其引导(bootstrapping)阶段之前就进行了这一操作。

因此解决方案为加入if __name__ == '__main__'作为程序入口点,同时加入freeze_support()函数,它会防止出现启动问题

from mulitproprocessing import freeze_support
freeze_support()

原理

在Python中,multiprocessing是一个支持同时执行多进程的包,它允许程序利用多个核心,进行并行计算。然而,多进程编程带来了一些挑战,特别是在不同操作系统之间,因为进程的创建和管理方式在Windows、Linux、和macOS等系统中有所不同。

Windows和Unix/Linux的差异

  • Unix/Linux:默认使用fork调用来创建子进程。fork调用后,子进程会复制父进程的所有内存空间和执行上下文,然后从fork调用返回点继续执行。这意味着子进程可以访问在fork之前定义的所有变量和资源。这种方式简化了进程间的数据共享,但也可能导致资源使用上的冲突。

  • Windows:没有fork调用。Python的multiprocessing模块通过创建一个新的Python解释器进程来启动子进程。这意味着每个子进程都是从头开始执行脚本的,而不是从父进程复制执行状态。因此,只有在if __name__ == '__main__':保护块内启动的代码才会执行。这避免了执行不必要的代码和潜在的递归进程创建,但也意味着需要显式地在父子进程间共享数据。

为什么需要if __name__ == '__main__':

这个保护语句确保当Python文件被运行时,只有在该文件作为主程序入口时代码块内的代码才会执行,而在导入到其他模块时不会执行。这是因为,当Python文件被导入时,__name__变量被设置为模块名,而不是'__main__'

在多进程环境下,这个机制尤其重要,因为它防止了在启动新进程时无意间执行模块级别的代码,这可能导致无限递归创建子进程的情况,从而引发程序崩溃或者其他不可预期的行为。

freeze_support()

freeze_support()函数是针对Windows平台的,当使用multiprocessing模块的程序被“冻结”为可执行文件时,这个函数必须被调用。在“冻结”程序(使用工具如PyInstaller或cx_Freeze创建独立的可执行文件)时,freeze_support()会检查是否正在执行一个冻结的可执行文件,如果是,则避免执行与multiprocessing相关的初始化代码,从而防止出现启动问题。

最后

if __name__ == '__main__':保护块和freeze_support()的使用是跨平台多进程编程的重要方面,确保了代码的正确初始化和安全执行。在Windows系统上,缺少这些机制可能导致上述错误,因为每个子进程都会尝试执行模块级别的代码,包括启动新的子进程,导致资源使用上的冲突和程序崩溃。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐