03.1
GIL 与选型
GIL(全局解释器锁)使同一进程内仅一个线程执行字节码。结论:CPU 密集用多进程,IO 密集用线程或 asyncio。
| 场景 | 推荐 |
|---|---|
| IO 密集(网络/磁盘) | threading / asyncio |
| CPU 密集(计算) | multiprocessing |
| 高并发连接 | asyncio |
03.2
threading
threading 适合 IO 并发。启动多个线程并行等待网络,主线程用 join 等待。
import threading
def fetch(url): ...
ts = [threading.Thread(target=fetch, args=(u,)) for u in urls]
[t.start() for t in ts]; [t.join() for t in ts]03.3
锁与队列
共享可变状态用 Lock 保护;线程间通信用 queue.Queue(线程安全),优于手动加锁。
import queue
q = queue.Queue()
q.put(item); item = q.get() # 线程安全03.4
multiprocessing
多进程绕过 GIL,真正并行利用多核;Pool 简化并行映射,代价是进程间通信开销。
from multiprocessing import Pool
with Pool(4) as p:
results = p.map(heavy_compute, data)03.5
asyncio 基础
asyncio 用单线程事件循环调度协程,在 IO 等待时切换,支撑海量并发连接。
import asyncio
async def main():
print("start")
await asyncio.sleep(1)
print("done")
asyncio.run(main())03.6
async/await 与并发
async 定义协程,await 挂起;asyncio.gather 并发运行多个协程。
async def fetch(u): ...
async def main():
results = await asyncio.gather(*(fetch(u) for u in urls))03.7
并发原语
asyncio 提供 Semaphore(限流)、Lock、Queue 等;注意阻塞调用(如 time.sleep)会卡住事件循环,要用 await asyncio.sleep。
别在协程里阻塞
在 asyncio 中调用同步阻塞函数会阻塞整个循环。用 run_in_executor 把阻塞任务丢到线程池。
03.8
常见陷阱
CPU 密集任务受 GIL 限制,多线程只是并发非并行。改用 multiprocessing 或释放 GIL 的 C 扩展(如 NumPy)。
requests 是阻塞同步库,会卡事件循环。异步场景用 aiohttp/httpx(async),或对同步调用用 run_in_executor。
03.9