总体结论 在 Ubuntu 上,Python 的多线程由 CPython 的 GIL(全局解释器锁) 与 操作系统线程共同决定:系统层面完全支持创建大量线程,同一进程可拥有成百上千条线程;但在 CPython 中,任意时刻只有一个线程能执行 Python 字节码。因此,多线程对 I/O 密集型任务(如网络、文件、数据库)非常有效;对 CPU 密集型任务难以线性利用多核,常需改用多进程或释放 GIL 的原生库来提升并行度。
适用场景与选择建议
| 场景类型 | 推荐方式 | 说明 |
|---|---|---|
| I/O 密集型(网络请求、文件读写、数据库) | 多线程 或 asyncio | 等待 I/O 时可释放 GIL,线程/协程并发能显著缩短总耗时 |
| CPU 密集型(数值计算、图像处理) | 多进程 或 释放 GIL 的 C/NumPy 内核 | 多进程绕过 GIL,充分利用多核;原生库在内部释放 GIL,可并行加速 |
| 混合型 | 线程 + 进程 或 asyncio + 进程池 | I/O 用线程/协程,计算用进程池,分工协同 |
| 以上结论与示例在 Ubuntu 上的行为与在其他 Linux 发行版一致,关键在于 GIL 的语义与任务类型匹配。 |
快速上手示例
import threading
def worker(n):
print(f"Thread-{n} start")
# 模拟I/O
import time; time.sleep(1)
print(f"Thread-{n} done")
threads = [threading.Thread(target=worker, args=(i,)) for i in range(3)]
for t in threads: t.start()
for t in threads: t.join()
from concurrent.futures import ThreadPoolExecutor, as_completed
def task(n):
import time; time.sleep(0.5)
return n * n
with ThreadPoolExecutor(max_workers=4) as pool:
futures = [pool.submit(task, i) for i in range(8)]
for f in as_completed(futures):
print("Result:", f.result())
# 计算密集型:用进程池或 NumPy(内部释放 GIL)
from concurrent.futures import ProcessPoolExecutor
import math
def heavy(x):
return sum(math.sin(i) ** 2 for i in range(10_000_000))
if __name__ == "__main__":
with ProcessPoolExecutor() as pool:
results = pool.map(heavy, range(4))
print(list(results))
上述写法在 Ubuntu 上可直接运行;I/O 密集用线程/协程,CPU 密集用进程或释放 GIL 的库效果更佳。
实践注意事项