在python中,我们可以通过concurrent.futures 的 ProcessPoolExecutor 创建多进程,实现并行方式,从而提高运算速度
举个例子,我们写了个一个函数fibonacci, 用于计算斐波那契数
# 计算斐波那契数的函数
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
如果我们是顺序运算,那么用时10.5秒,平均每个任务2秒。
%%time
# 顺序计算斐波那契数
def compute_fibonacci(numbers):
for num in numbers:
result = fibonacci(num)
print(f'Fibonacci({num}) = {result}')
# 要计算的斐波那契数列表
numbers = [35, 35, 35, 35, 35]
compute_fibonacci(numbers)
# 时间
CPU times: user 10.5 s, sys: 0 ns, total: 10.5 s
Wall time: 10.5 s
如果是并行运算,那么用时只需要2.36 s,比原来快了将近4倍。
%%time
from concurrent.futures import ProcessPoolExecutor, as_completed
# 使用 ProcessPoolExecutor 计算斐波那契数
def compute_fibonacci(numbers):
# 创建 ProcessPoolExecutor
with ProcessPoolExecutor() as executor:
# 提交任务到进程池
futures = [executor.submit(fibonacci, num) for num in numbers]
# 等待每个任务完成并获取结果
for future in as_completed(futures):
result = future.result()
print(f'Result: {result}')
# 要计算的斐波那契数列表
numbers = [35, 35, 35, 35, 35]
compute_fibonacci(numbers)
# 时间
CPU times: user 16.6 ms, sys: 140 ms, total: 157 ms
Wall time: 2.36 s
需要注意的是,我们案例用的是numbers = [35, 35, 35, 35, 35]
, 假设,我们换成 numbers = [1] * 100
, 那么顺序执行只需要485 µs,而并行却需要2.35 s,反而速度更慢了。
根据上述案例,就可以得到关于python加速的一个心得,无脑多进程不可取,因为多进程存在额外开销,例如
- 进程创建和管理:ProcessPoolExecutor 使用多进程并行处理任务,进程的创建和管理(启动、通信、结束)本身就有一定的开销。对于非常快速的计算任务(如计算斐波那契数1),这种开销可能远远超过了任务本身的计算时间。
- 任务分配和结果收集:在并行执行时,每个任务都需要从主进程发送到工作进程,然后工作进程完成计算后,结果还需要发送回主进程。这个过程涉及到序列化和反序列化数据,以及进程间通信的开销,这些都会影响总体执行时间。
因此,在使用concurrent模块时,需要先用少量数据测试下是否真的值得并行。