Python中for 和 async for 的两种循环的核心区别,一文详解!(附代码示例)
for 和 async for 的核心区别在于:你在等“下一个数据”的时候,能不能干别的事。
简单来说:
-
普通
for:是阻塞的。拿不到下一个数据,全程序卡死在那里等。 -
async for:是非阻塞的。在等下一个数据生成的间隙(比如等网络包、等数据库查询),程序可以去处理别的任务。
Async 的真正威力在于“同时做多件事”。
要看出区别,我们需要引入一个 “背景任务”(比如一个正在转圈的 Loading 动画,或者是背景心跳)。
-
普通 For 循环:在等待数据时,整个世界都冻结了,背景动画会卡死。
-
Async For 循环:在等待数据时,背景动画还在跑。
请运行下面这两段代码,差异非常巨大,可以方便更直观理解这两种循环的差异:
场景:一边下载大文件(模拟),一边播放 Loading 动画
1. ❌ 普通 For 循环(同步/阻塞)
你会发现:程序运行时,在这个 1 秒的等待期间,整个程序像“死机”了一样,没有任何反应,你也无法插入任何背景任务。
import time print("=== 1. 普通同步模式开始 ===") def sync_stream(): for i in range(3): print(f"🔄 (生成器内部) 正在用力下载第 {i+1} 个包...") time.sleep(1) # 【死等】这里卡住了,CPU 不能去干别的事 yield f"📦 包 {i+1} 下载完成" start_time = time.time() # 主循环 for data in sync_stream(): # 在拿到 data 之前,这里是一片死寂,什么都做不了 print(f"✅ 主程序收到: {data}\n") print(f"=== 同步模式结束,总耗时: {time.time() - start_time:.2f}秒 ===")
实际执行效果:

2. ✅ Async For 循环(异步/非阻塞)
请仔细观察输出: 你会看到在 async for 等待数据的空档期,屏幕上还在不断打印 "💓 咚-咚-咚"。
这证明了:async for 在等待时,让出了控制权,让背景任务(心跳)有机会运行!
import asyncio import time print("\n\n=== 2. 异步模式开始 (请注意观察心跳) ===") # 这是一个背景任务,模拟 UI 动画或者心跳检测 async def background_heartbeat(): while True: print(" 💓 (背景任务) 咚-咚-咚... 程序还活着!") await asyncio.sleep(0.3) # 每0.3秒跳动一次 # 异步生成器 async def async_stream(): for i in range(3): print(f"🔄 (生成器内部) 正在用力下载第 {i+1} 个包...") # 【挂起】告诉 Python:我要等1秒,这期间你去处理那个“心跳”任务吧 await asyncio.sleep(1) yield f"📦 包 {i+1} 下载完成" async def main(): # 1. 启动背景心跳任务 task = asyncio.create_task(background_heartbeat()) start_time = time.time() # 2. 开始 Async For 循环 # 关键点:每次在这里“等”数据的时候,上面的 background_heartbeat 就会插队运行 async for data in async_stream(): print(f"✅ 主程序收到: {data}\n") # 停止心跳任务 task.cancel() print(f"=== 异步模式结束,总耗时: {time.time() - start_time:.2f}秒 ===") # 运行 asyncio.run(main())
实际执行效果:

直观差异图解
差异总结:
-
普通
for(Block):-
就像你去排队买奶茶。
-
在店员做奶茶的 5 分钟里,你必须傻站在柜台前,不能玩手机,不能去厕所,完全被锁死。
-
-
async for(Non-Block):-
就像你去拿号买奶茶。
-
店员说“要等 5 分钟”,你拿到号(
await)。 -
在这 5 分钟里,你可以去隔壁买个面包,或者回个微信(运行背景任务)。
-
等奶茶好了(
yield),你再回来取。
-
在上面的代码中,那个不断打印的 💓 咚-咚-咚 就是你在等待期间去买的面包。普通 for 循环是吃不到这个面包的。

浙公网安备 33010602011771号