订阅更新

多线程为什么没有加速CPU密集任务——Python并发编程

Python手册 第 11 题 约 4 分钟读完

本文目录
  1. 先说结论
  2. 三套方案对比
  3. 实战经验:数据校验从120秒到35秒
  4. concurrent.futures——统一接口
  5. 面试高频追问
  6. 总结

先说结论

选择标准:CPU密集用multiprocessing(多进程绕过GIL);IO密集用asyncio或threading(GIL等IO时释放);混合任务用multiprocessing+asyncio组合。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

三套方案对比

方案原理适用GIL影响大数据应用
threading多线程共享内存IO密集受限并行调API
multiprocessing多进程独立内存CPU密集不受限并行数据校验
asyncio单线程协程高并发IO不受限百个API并发
# threading——IO密集场景
import threading
def fetch_data(url):
    return requests.get(url).json()
threads = [threading.Thread(target=fetch_data, args=(url,)) for url in urls]
for t in threads: t.start()
for t in threads: t.join()
# 5个API各2秒,串行10秒,5线程并行2秒
 
# multiprocessing——CPU密集场景
from multiprocessing import Pool
def validate_table(name):
    df = pd.read_parquet(f's3://data/{name}.parquet')
    return len(check_nulls(df) + check_ranges(df))
with Pool(4) as pool:
    results = pool.map(validate_table, tables)
# 4张表各30秒,串行120秒,4进程35秒
# asyncio——高并发IO
import asyncio, aiohttp
async def fetch(session, url):
    async with session.get(url) as r: return await r.json()
async def main():
    async with aiohttp.ClientSession() as s:
        tasks = [fetch(s, u) for u in urls]
        return await asyncio.gather(*tasks)
# 100个API各2秒,串行200秒,asyncio约3秒

实战经验:数据校验从120秒到35秒

在某知名出海硬件品牌,4张核心表串行校验120秒。threading无效(CPU 25%),改multiprocessing后CPU 100%,35秒完成。

教训:CPU密集用threading无效是Python新手最常犯的错。看到CPU上不去就该想到GIL。

concurrent.futures——统一接口

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
# IO密集用ThreadPoolExecutor
with ThreadPoolExecutor(10) as e:
    results = list(e.map(fetch_api, urls))
# CPU密集用ProcessPoolExecutor
with ProcessPoolExecutor(4) as e:
    results = list(e.map(validate, tables))

面试高频追问

追问一:多进程之间怎么共享数据?

Pool.map()的返回值传回主进程(最简单推荐);或multiprocessing.Queue进程间队列。

追问二:asyncio和多线程能混用吗?

可以。asyncio.to_thread(func)在事件循环中调用同步函数。

追问三:Python 3.13的no-GIL?

实验性支持。成熟后threading就能真正并行CPU任务。但目前NumPy/Pandas还没适配,短期multiprocessing仍是标准方案。

总结

并发面试讲三套方案选择:threading用于IO密集,multiprocessing用于CPU密集,asyncio用于高并发IO。GIL是关键——CPU密集用threading无效。能讲出校验脚本从threading无效到multiprocessing 3.4倍提升的经历,面试官觉得你理解了GIL的实际影响。

下一篇聊Python包管理:requirements.txt和虚拟环境的正确用法。

你们Python脚本用什么并发方案?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,只讲大数据面试干货

刷题进度保存在当前浏览器