multiprocessing在Windows环境编译器下的问题


一个久未解决的问题

运行环境:

操作系统:Windows 10 10.0
版本:10.0.17763 版本 17763
处理器:Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz,2208 Mhz,6 个内核,12 个逻辑处理器
编译器:PyCharm 2018.3.4 (Community Edition)
Build:#PC-183.5429.31, built on January 29, 2019
Python:3.7.0

在学习多进程的时候,multiprocessing模块就是跨平台版本的多进程模块。multiprocessing模块提供了一个Process类来代表一个进程对象,代码可以在编译器中直接运行:(找了一个简单的吐槽版代码)

import multiprocessing
import time

def action(a, b):  # 待会两个进程要执行的任务↓
    for i in range(30):  # 循环30次
        print(a, ' ', b)
        time.sleep(0.1)  # 等待0.1s

if __name__ == '__main__':  # 这行代码很重要,新建进程

    jc1 = multiprocessing.Process(target=action, args=('进程一', 0))  # 准备建立一个进程:multiprocessing.Process()
    jc2 = multiprocessing.Process(target=action, args=('进程二', 1))  # 再准备建立一个新进程,这是基本格式记住←
    # 必要参数target:指定进程要执行的任务(这里是执行函数 action),必要参数args:直译成中文就是'参数',顾名思义就是前面target的参数,即action的参数,注意args是个元组,所以args后的参数写成tuple元组格式。直接写target('进程一',0)一定报错的

    jc1.start()  # 将蓄势待发的jc1进程正式启动!!
    jc2.start()  # 同上...

    jc1.join()  # 等待进程jc1将任务执行完...
    jc2.join()  # ...
    print('jc1,jc2任务都已执行完毕')

    jc1.close()  # 彻底关闭进程jc1
    jc2.close()  # ...

输出:

进程一   0
进程二   1
进程一   0
进程二   1
进程一   0
进程二   1
...

但是,当我们使用pool时,如:

from multiprocessing import Pool
import multiprocessing

def f(x):
    return x*x

if __name__ == '__main__':
    multiprocessing.freeze_support()
    with Pool(5) as p:
        print(p.map(f, [1, 2, 3]))

则无任何输出,进程卡死。但是如果用cmd运行:

python main.py

则很快会显示输出:

[1, 4, 9]

一些解释

因为Windows缺乏linix的fork, 所以它会有一些额外的限制:

  • 不管是绑定还是未绑定的方法, 都不要直接作为参数传给Process初始化的target, 相反应该要用普通的函数代替
  • 子进程在访问全局变量时, 可能会与父进程的值不同. ( 模块级别的常量没这问题 )
  • 开启新Python解析器或者创建新process时, 确定主模块能够安全的导入.
    也有文章说要加入multiprocessing.freeze_support()函数,但是试了一下没有成功。
    为此,尝试以下试验:
  1. 使用python3.7+VS Code,可以运行。
  2. 使用python3.6+Pycharm,无法运行。
  3. 结合python3.7+pycharm,无法运行的结果,
    最终根据以上试验,确认原因应该是pycharm与python3.7不兼容原因。(不知道有没有解决方法,先改用VS Code吧)

评论
  目录