并发编程是Python进阶核心分水岭,是爬虫、接口服务、异步任务、高并发项目的必备能力。Python提供多线程、多进程、异步IO三套并发方案,三者适用场景、底层原理、优缺点差异极大,绝大多数新手的并发报错、效率低下、卡死问题,均是选型错误导致。
本文全覆盖指定重难点:threading多线程、multiprocessing多进程、asyncio事件循环、async/await异步语法、Future未来对象、aiohttp异步请求。全程搭配可落地实战代码、底层原理拆解、工程高频坑点、大厂面试真题,一站式吃透Python全场景并发体系。
一、并发核心基础认知
1.1 并发与并行区别
并发:单核CPU快速切换多个任务,宏观同时执行,微观交替执行,解决IO阻塞等待问题;
并行:多核CPU同时执行多个任务,真正意义上的同时运行,解决CPU密集计算问题。
1.2 Python三大并发方案选型
1、多线程 threading:适配IO密集任务,受GIL锁限制,无法利用多核,线程开销极小;
2、多进程 multiprocessing:适配CPU密集任务,突破GIL限制,利用多核CPU,进程开销大;
3、异步IO asyncio:超高IO并发场景,单线程协程,无线程切换开销,并发量级远超多线程。
1.3 核心关键:GIL全局解释器锁
GIL是Python经典核心痛点:同一时刻一个进程内只有一个线程执行Python代码。
后果:多线程无法实现CPU并行,仅适合IO阻塞场景;CPU密集任务必须用多进程。
二、多线程 threading(IO密集首选)
线程是进程内的最小执行单元,共享进程资源,创建销毁开销极低,适合文件读写、网络请求、接口等待等IO阻塞型任务。
2.1 多线程基础实战
import threading
import time
def task(name, delay):
print(f"线程 {name} 启动,等待 {delay}s")
time.sleep(delay) # 模拟IO阻塞
print(f"线程 {name} 执行完成")
if __name__ == "__main__":
t1 = threading.Thread(target=task, args=("线程1", 2))
t2 = threading.Thread(target=task, args=("线程2", 1))
t1.start()
t2.start()
# 阻塞主线程,等待子线程执行完毕
t1.join()
t2.join()
print("所有线程执行完毕")
2.2 守护线程
设置 daemon=True 开启守护线程,主线程退出时,守护线程会强制终止,无需等待执行完毕,适合后台轮询、日志监控等附属任务。
import threading
import time
def daemon_task():
while True:
print("守护线程运行中...")
time.sleep(1)
if __name__ == "__main__":
t = threading.Thread(target=daemon_task, daemon=True)
t.start()
time.sleep(3)
print("主线程退出,守护线程随之终止")
2.3 线程安全与锁机制(高频坑点)
多线程共享全局变量,并发修改会出现数据错乱,需通过线程锁保证数据一致性。
import threading
num = 0
lock = threading.Lock()
def add_count():
global num
for _ in range(100000):
lock.acquire() # 加锁
num += 1
lock.release() # 解锁
if __name__ == "__main__":
t1 = threading.Thread(target=add_count)
t2 = threading.Thread(target=add_count)
t1.start()
t2.start()
t1.join()
t2.join()
print("最终计数:", num) # 正确结果200000
三、多进程 multiprocessing(CPU密集首选)
多进程会创建多个独立进程,每个进程拥有独立GIL锁,可充分利用多核CPU,彻底突破多线程的性能瓶颈,适合数值计算、数据分析、模型推理等CPU密集任务。
核心特点:进程间资源完全隔离、无共享变量、开销大于线程、支持多核并行。
3.1 多进程基础实战
import multiprocessing
import time
def cpu_task(num):
# 模拟CPU密集计算
res = 0
for i in range(num):
res += i ** 2
print(f"进程 {multiprocessing.current_process().name} 计算完成")
if __name__ == "__main__":
p1 = multiprocessing.Process(target=cpu_task, args=(1000000,))
p2 = multiprocessing.Process(target=cpu_task, args=(1000000,))
p1.start()
p2.start()
p1.join()
p2.join()
print("所有进程执行完毕")
3.2 进程间通信(Queue队列)
进程资源隔离,无法直接共享变量,通过Queue队列实现安全数据交互。
import multiprocessing
def send_msg(q):
q.put("进程数据通信测试")
def recv_msg(q):
print("接收数据:", q.get())
if __name__ == "__main__":
q = multiprocessing.Queue()
p1 = multiprocessing.Process(target=send_msg, args=(q,))
p2 = multiprocessing.Process(target=recv_msg, args=(q,))
p1.start()
p2.start()
3.3 进程池(工程高频)
频繁创建销毁进程开销极大,进程池可复用进程资源,控制并发数量,适合批量任务处理。
import multiprocessing
def pool_task(x):
return x * x
if __name__ == "__main__":
# 开启4个进程的进程池
with multiprocessing.Pool(processes=4) as pool:
res = pool.map(pool_task, [1,2,3,4,5])
print("批量计算结果:", res)
四、asyncio异步IO核心体系(高并发IO终极方案)
asyncio是Python原生异步编程框架,基于事件循环实现单线程协程并发,无线程/进程切换开销,IO并发量级远超多线程、多进程,是爬虫、异步接口、高并发服务的核心方案。
4.1 核心概念:事件循环
**事件循环(Event Loop)**是异步程序的调度核心,负责监听、调度、执行所有协程任务,自动切换阻塞任务,实现异步并发。
执行逻辑:循环检测所有任务 → 就绪任务立即执行 → 阻塞任务挂起 → 等待IO完成后唤醒继续执行。
4.2 async/await 异步语法
1、async:修饰普通函数为协程函数,调用后不执行,仅生成协程对象;
2、await:阻塞等待异步任务完成,主动让出CPU权限,让事件循环执行其他任务。
核心规则:await 只能写在 async 函数内部。
4.3 基础异步实战
import asyncio
# 定义协程函数
async def async_task(name, delay):
print(f"异步任务 {name} 启动,等待 {delay}s")
await asyncio.sleep(delay) # 异步阻塞,不占用CPU
print(f"异步任务 {name} 执行完成")
async def main():
# 创建多个协程任务
task1 = asyncio.create_task(async_task("A", 2))
task2 = asyncio.create_task(async_task("B", 1))
# 等待所有任务执行完毕
await task1
await task2
if __name__ == "__main__":
# 启动事件循环,运行主协程
asyncio.run(main())
五、Future未来对象(异步底层核心)
Future 是 asyncio 异步编程的底层基础对象,代表一个未来即将完成的任务结果,协程Task是Future的子类。
核心作用:存储异步任务的执行状态、返回结果、异常信息,实现任务结果的异步回调与等待。
5.1 Future核心实战
import asyncio
async def set_future_result(future):
await asyncio.sleep(2)
future.set_result("Future任务执行完成!")
async def main():
# 创建Future对象
future = asyncio.Future()
# 启动任务为Future赋值
await asyncio.create_task(set_future_result(future))
# 等待Future获取结果
result = await future
print(result)
if __name__ == "__main__":
asyncio.run(main())
5.2 Future与Task区别
1、Future:底层抽象对象,仅负责存储结果、状态,无执行逻辑;
2、Task:Future子类,用于包装协程函数,具备调度执行能力,是实际运行的异步任务。
六、aiohttp异步网络请求(工程高频)
Python原生不支持异步HTTP请求,aiohttp是专门为asyncio设计的异步网络请求库,替代同步requests库,可实现超高并发爬虫、异步接口调用,并发效率远超多线程爬虫。
6.1 环境安装
# 安装异步请求库
# pip install aiohttp
6.2 aiohttp高并发请求实战
import aiohttp
import asyncio
# 异步请求函数
async def fetch(session, url):
async with session.get(url) as resp:
status = resp.status
text = await resp.text()
print(f"请求地址:{url},状态码:{status}")
return text
async def main():
# 创建异步会话(全局复用,性能更高)
async with aiohttp.ClientSession() as session:
url_list = [
"https://www.baidu.com",
"https://www.bing.com",
"https://www.csdn.net"
]
# 批量创建异步任务
tasks = [fetch(session, url) for url in url_list]
# 并发执行所有任务
await asyncio.gather(*tasks)
if __name__ == "__main__":
asyncio.run(main())
6.3 aiohttp核心规范
1、必须使用 ClientSession 发起请求,禁止频繁创建销毁会话;
2、所有请求、响应读取操作必须加 await;
3、异步IO场景优先aiohttp,同步场景使用requests,禁止混用。
七、三大并发方案选型总结(工程准则)
1、IO密集任务(网络请求、文件读写、数据库查询):优先 asyncio + aiohttp,超高并发;简单少量IO任务可用 threading 多线程;
2、CPU密集任务(计算、解析、建模):必须用 multiprocessing 多进程,突破GIL多核并行;
3、绝对禁止:CPU密集用多线程、IO密集用多进程(资源浪费、效率极低)。
八、高频工程坑点汇总
1、GIL误区:多线程不能多核并行,仅加速IO任务,CPU任务无效;
2、进程开销:进程创建销毁开销大,批量任务优先进程池复用;
3、异步阻塞坑:异步函数中禁止使用time.sleep、requests同步方法,会阻塞整个事件循环,必须用异步对应API;
4、Future空结果:未set_result的Future会永久阻塞,需做好异常捕获;
5、aiohttp会话复用:频繁创建ClientSession会造成端口耗尽,必须全局复用。
九、高频面试真题汇总
题目1:GIL全局解释器锁是什么?带来什么影响?
答案:GIL是CPython的全局锁,保证同一时刻一个进程内只有一个线程执行代码。导致Python多线程无法实现CPU多核并行,仅适合IO密集任务,CPU密集任务必须使用多进程。
题目2:线程、进程、协程的区别?
答案:线程轻量、共享资源、受GIL限制,适配IO密集;进程独立隔离、支持多核、开销大,适配CPU密集;协程单线程异步、无切换开销、并发量最高,适配超高IO并发。
题目3:asyncio事件循环的作用?async/await原理?
答案:事件循环是异步任务调度核心,负责统筹所有协程任务的执行、挂起、唤醒;async定义协程函数,await主动让出CPU,等待IO完成,实现单线程异步并发。
题目4:Future和Task的关系?
答案:Future是底层结果容器,存储任务状态和返回值,无执行能力;Task继承自Future,用于包装协程,具备任务调度执行能力,是异步任务的实际载体。
题目5:aiohttp和requests的区别?
答案:requests是同步请求,阻塞等待响应,并发效率低;aiohttp是异步请求,基于asyncio实现,非阻塞并发,适合高并发爬虫、异步服务,是异步网络请求标准方案。
十、全文终极背诵总结
1、多线程threading:轻量IO并发,共享资源,需线程锁,受GIL限制,不适合计算任务。
2、多进程multiprocessing:多核并行,突破GIL,资源隔离,开销大,专属CPU密集计算场景。
3、asyncio事件循环:异步调度核心,统筹所有协程任务,实现非阻塞高并发。
4、async/await:异步专属语法,async定义协程,await阻塞等待并让出CPU,是异步编程基础。
5、Future:异步底层结果容器,存储任务状态与结果,Task为其子类,负责任务执行调度。
6、aiohttp:异步HTTP请求库,替代同步requests,适配asyncio,实现超高并发网络请求。
7、核心选型:IO用异步/多线程,CPU用多进程,严格区分场景,规避性能瓶颈。