为何使用ThreadPoolExecutor无法提升Python代码运行速度?
问题分析与解决
为什么多线程没提速反而变慢?
核心原因是Python的全局解释器锁(GIL):
- CPython解释器有个机制,同一时间只能有一个线程执行Python字节码,哪怕你用的是多核CPU。
- 你的
sum_list是纯CPU密集型任务,多线程下不仅没法并行计算,还会因为线程频繁争夺GIL、切换上下文额外消耗资源,导致速度不升反降——Windows系统线程切换成本更高,所以变慢更明显。
用线程机制能让这个函数更快吗?
不行。只要是基于CPython的线程方案(包括ThreadPoolExecutor),都绕不开GIL的限制,没法真正并行执行CPU密集型的Python代码,自然没法提速。
真正有效的提速方案
1. 换用多进程
用ProcessPoolExecutor代替ThreadPoolExecutor,每个进程有独立的解释器和GIL,能真正利用多核并行计算:
import time import concurrent.futures def sum_list(thelist:list, start:int, end:int): s = 0 for i in range(start,end): s += thelist[i]**3//10 return s LISTSIZE = 5000000 big_list = list(range(LISTSIZE)) THREADCOUNT=4 SUBLISTSIZE = LISTSIZE//THREADCOUNT start = time.perf_counter() with concurrent.futures.ProcessPoolExecutor(THREADCOUNT) as executor: futures = [executor.submit(sum_list, big_list, i*SUBLISTSIZE, (i+1)*SUBLISTSIZE) for i in range(THREADCOUNT)] big_sum = 0 for res in concurrent.futures.as_completed(futures): big_sum += res.result() print(f"{THREADCOUNT} processes: sum={big_sum}, time={time.perf_counter()-start} sec")
注意:进程间传递数据有开销,但你的任务粒度足够大,能明显看到提速效果。
2. 用NumPy优化计算逻辑
NumPy的底层是C实现,能避开GIL,向量操作比Python循环高效得多:
import time import numpy as np LISTSIZE = 5000000 big_array = np.arange(LISTSIZE) start = time.perf_counter() big_sum = (big_array**3 // 10).sum() print(f"NumPy version: sum={big_sum}, time={time.perf_counter()-start} sec")
这种方式甚至比多进程更快,因为它的计算逻辑是高度优化的。
3. JIT编译加速
用numba给函数加JIT装饰器,直接把Python代码编译成机器码,绕过GIL:
import time from numba import jit @jit(nopython=True) def sum_list(thelist:list, start:int, end:int): s = 0 for i in range(start,end): s += thelist[i]**3//10 return s LISTSIZE = 5000000 big_list = list(range(LISTSIZE)) start = time.perf_counter() big_sum=sum_list(big_list, 0, LISTSIZE) print(f"Numba JIT: sum={big_sum}, time={time.perf_counter()-start} sec")
内容的提问来源于stack exchange,提问作者Erel Segal-Halevi
相关产品推荐
相关产品推荐

