← 返回首页

Python 并发与异步:threading、多进程与 asyncio 实战

10/23/2025

Python 并发与异步:threading、多进程与 asyncio 实战

Python 并发与异步:threading、多进程与 asyncio 实战

当程序需要同时处理大量 I/O 或计算任务,并发就会显得重要。Python 存在 GIL(全局解释器锁),因此需要理解 I/O 与 CPU 的差异:

  • I/O 密集:网络请求、磁盘读写,适合多线程或 asyncio
  • CPU 密集:图像处理、数值计算,适合多进程或 C 扩展。

一、线程(threading)适合 I/O

import threading
import time

results = []

def io_task(i: int):
    time.sleep(0.2)  # 模拟 I/O 等待
    results.append(f"done-{i}")

threads = [threading.Thread(target=io_task, args=(i,)) for i in range(10)]
[t.start() for t in threads]
[t.join() for t in threads]
print(results)

优点:API 简单,生态成熟。缺点:共享状态易出错,需要锁与队列。

二、多进程(multiprocessing)适合 CPU

from multiprocessing import Pool

def heavy(x: int) -> int:
    s = 0
    for _ in range(1_000_00):
        s += x * x
    return s

with Pool(processes=4) as pool:
    out = pool.map(heavy, range(8))
print(out)

优点:绕过 GIL,CPU 利用率高。缺点:进程间通信成本大,启动慢。

三、异步(asyncio)适合大量 I/O

asyncio 通过事件循环调度协程,让单线程并行等待多个 I/O。

import asyncio

async def fetch(i: int) -> str:
    await asyncio.sleep(0.2)
    return f"res-{i}"

async def main():
    tasks = [fetch(i) for i in range(10)]
    results = await asyncio.gather(*tasks)
    print(results)

asyncio.run(main())

优点:资源占用低、吞吐高。缺点:调试困难、同步代码迁移成本。

四、选择策略与混合架构

  • I/O 密集:优先 asyncio;简单场景可用 threading
  • CPU 密集:优先 multiprocessing,或借助 numba/C 扩展。
  • 混合:网络层 asyncio,计算层子进程;用队列/消息总线解耦。

五、实战建议

  • 控制并发度:避免过多任务导致资源耗尽(连接数、文件句柄)。
  • 超时与重试:对外部服务设定超时、指数退避重试;记录错误原因。
  • 背压与限流:队列长度与生产消费速率要匹配,避免积压。
  • 可观测性:为协程/线程添加上下文日志,附带请求 ID。

结语

并发没有银弹。先判断任务类型(I/O vs CPU),再选择合适模型,并在可观测性与错误处理上做好工程化建设,才能让性能与稳定性真正提升。