一个久未解决的问题
运行环境:
操作系统: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()函数,但是试了一下没有成功。
为此,尝试以下试验:
- 使用python3.7+VS Code,可以运行。
- 使用python3.6+Pycharm,无法运行。
- 结合python3.7+pycharm,无法运行的结果,
最终根据以上试验,确认原因应该是pycharm与python3.7不兼容原因。(不知道有没有解决方法,先改用VS Code吧)