python因为其全局解释器锁GIL而无法通过线程实现真正的并行计算。这个论断我们不展开,但是有个概念我们要说明,IO密集型 vs. 计算密集型。
IO密集型:读取文件,读取网络套接字频繁。
计算密集型:大量消耗CPU的数学与逻辑运算,也就是我们这里说的并行计算。
而concurrent.futures模块,可以利用multiprocessing实现真正的并行计算。
核心原理是:concurrent.futures会以子进程的形式,平行的运行多个python解释器,从而令python程序可以利用多核CPU来提升执行速度。
由于子进程与主解释器相分离,所以他们的全局解释器锁也是相互独立的。每个子进程都能够完整的使用一个CPU内核。
1. 不采用并行
importglobimportosimportcv2for img_name in glob.glob('*.jpg'):
img=cv2.imread(img_name)
img= cv2.resize(img, (600, 600))
2. 多进程
importglobimportosimportcv2importconcurrent.futuresdefload_and_resize(img_name):
img=cv2.imread(img_name)
img= cv2.resize(img, (600, 600))#Creat a pool of processes. By default, one is created for each CPU in your machine.
with concurrent.futures.ProcessPoolExecutor() as executor:
img_name= glob.glob('*.jpg')
executor.map(load_and_resize, img_name)
是否总能大幅加速?
当你有要处理的数据列表并且要对每个数据点执行类似的计算时,使用Python并行池是一个很好的解决方案。
但是,它并不总是完美的。并行池处理的数据不会以任何可预测的顺序处理。如果你需要处理的结果按特定顺序排列,那么这种方法可能不适合。
你处理的数据还必须是Python知道如何“pickle”的类型。幸运的是,这些类型很常见。以下来自Python官方文档:
None, True, 及 False
整数,浮点数,复数
字符串,字节,字节数组
仅包含可选对象的元组,列表,集合和词典
在模块的顶层定义的函数(使用def,而不是lambda)
在模块顶层定义的内置函数
在模块顶层定义的类
这些类的实例,__dict__或调用__getstate __()的结果是可选择的