Python多线程计算数组求和为何更慢?求原理解析
Python多线程计算数组和耗时更高的原因解析
问题场景与代码
我正在学习Python threading,尝试通过多线程计算数组的和:用一个线程计算数组前半部分的和,另一个线程计算后半部分的和,并统计耗时。以下是实现代码:
import threading import math import time def part_summa0(arr, i, j): global summ0 for e in range(i, j): summ0 += arr[e] def part_summa1(arr, i, j): global summ1 for e in range(i, j): summ1 += arr[e] def threads(arr): threads = [] threads.append(threading.Thread(target=part_summa0, args=(arr, 0, len(arr)//2))) threads.append(threading.Thread(target=part_summa1, args=(arr, len(arr)//2, len(arr)))) for thread in threads: thread.start() for thread in threads: thread.join() l = list(range(1,100000000)) summ0 = 0 summ1 = 0 start = time.time() part_summa0(l, 0, len(l)) print(summ0) print(time.time()-start) summ0 = 0 summ1 = 0 start = time.time() threads(l) print(summ0+summ1) print(time.time()-start)
运行输出如下:
4999999950000000 8.55412483215332 4999999950000000 15.346555471420288
实际测试发现多线程的耗时远高于单线程,请问为何Python中该多线程操作更慢?其工作原理是什么?
原因解析
核心问题:GIL(全局解释器锁)的限制
CPython解释器中存在一把全局解释器锁(GIL),这把锁的核心规则是:同一时间只能有一个线程执行Python字节码。
你的代码属于纯CPU密集型任务(循环累加数组元素),两个线程都在争抢GIL的使用权。由于GIL的限制,两个线程无法真正并行执行,只能交替获取GIL来运行。而线程切换的过程(释放GIL、切换上下文、重新获取GIL)会产生额外的性能开销,这就导致多线程版本的总耗时反而比单线程更长。
GIL的工作原理
GIL是CPython为了简化内存管理而设计的:它避免了多线程同时操作Python对象时出现的竞态条件和内存安全问题。但它的存在对任务类型有明显的区分:
- 对于IO密集型任务(比如网络请求、文件读写),线程在等待IO操作完成时会主动释放GIL,此时其他线程可以获取GIL执行任务,多线程能有效提升效率;
- 对于CPU密集型任务,线程会持续占用CPU执行字节码,不会频繁释放GIL,其他线程只能等待当前线程释放GIL后才能运行,不仅无法利用多核CPU,还会因为线程切换增加额外开销。
解决方向
如果要处理CPU密集型任务,应该使用多进程(比如multiprocessing模块)。每个进程拥有独立的Python解释器和GIL,能够真正利用多核CPU并行执行任务,避免GIL的限制。也可以使用concurrent.futures.ProcessPoolExecutor来简化多进程的实现流程。
内容的提问来源于stack exchange,提问作者Kirill Stepankov
相关产品推荐
相关产品推荐

