0%

python多进程-multiprocessing

本文是关于python中多进程的使用,提高运行速度。

官方文档

multiprocessing 是一个支持使用与 threading 模块类似的 API 来产生进程的包。 multiprocessing 包同时提供了本地和远程并发操作,通过使用子进程而非线程有效地绕过了 全局解释器锁。 因此,multiprocessing 模块允许程序员充分利用给定机器上的多个处理器。 它在 Unix 和 Windows 上均可运行。 multiprocessing 模块还引入了在 threading 模块中没有的API。一个主要的例子就是 Pool 对象,它提供了一种快捷的方法,赋予函数并行化处理一系列输入值的能力,可以将输入数据分配给不同进程处理(数据并行)。下面的例子演示了在模块中定义此类函数的常见做法,以便子进程可以成功导入该模块。

学习案例

使用 time.sleep 来模拟一个函数可能会耗费大量时间。

1
2
3
4
5
6
7
import time
from multiprocessing import Pool

def func(x):
time.sleep(2)
print(x**2, end=' | ')
return x**2

普通调用函数

首先使用普通方法多次调用,这里使用 map() 函数,也可以选择使用循环。

1
2
3
4
5
6
if __name__ == '__main__':
start_time = time.time()
# list函数使得map解析,否则不会触发map
list(map(func, [i for i in range(10)]))
end_time = time.time()
print(f"\n一共耗时{end_time-start_time}")

输出结果

1
2
0 | 1 | 4 | 9 | 16 | 25 | 36 | 49 | 64 | 81 |
一共耗时20.07989525794983

使用进程池调用函数

这里使用进程池的 map 方法

map(func, iterable[, chunksize])

内置 map() 函数的并行版本 (但它只支持一个 iterable 参数,对于多个可迭代对象请参阅 starmap())。它会保持阻塞直到获得结果。 这个方法会将可迭代对象分割为许多块,然后提交给进程池。可以将 chunksize 设置为一个正整数从而(近似)指定每个块的大小可以。 注意对于很长的迭代对象,可能消耗很多内存。可以考虑使用 imap()imap_unordered() 并且显示指定 chunksize 以提升效率。

1
2
3
4
5
6
7
if __name__ == '__main__':
start_time = time.time()
with Pool(5) as p:
p.map(func, [i for i in range(10)])
# list(map(func, [i for i in range(10)]))
end_time = time.time()
print(f"\n一共耗时{end_time-start_time}")

输出结果

1
2
0 | 36 | 1 | 49 | 4 | 25 | 9 | 64 | 16 | 81 | 
一共耗时4.738358020782471

结论

可以发现,使用普通的方法对同一个复杂函数调用多次,那么将会花费线性时间来处理。

而当使用了 multiprocessing.Pool 时,那么则会使得该函数并行处理,效率得到极大提升。

参考

个人收获

在华为一面中遇到问关于数据处理时,面对大量数据如何进行读取,是否会多线程的使用时有所欠缺,这次的学习使得补充了这部分的知识点,至于工作中可能会使用的更多方法则需要进一步了解。

------ 本文结束------