time.sleep vs asyncio.sleep 详解
time.sleep vs asyncio.sleep 详解
概述
time.sleep 和 asyncio.sleep 都是用于暂停程序执行的函数,但它们的工作原理完全不同:
| 特性 | time.sleep | asyncio.sleep |
|---|---|---|
| 类型 | 同步阻塞函数 | 异步协程函数 |
| 阻塞范围 | 阻塞整个线程 | 只阻塞当前协程 |
| 使用方式 | 直接调用 | 必须用 await 调用 |
| 适用场景 | 同步代码/多线程 | 异步代码/事件循环 |
| 并发性能 | 阻塞期间无法处理其他任务 | 释放控制权,允许其他任务运行 |
1. time.sleep - 阻塞式延迟
工作原理
import time
def sync_task():
print("开始执行")
time.sleep(3) # 阻塞整个线程3秒
print("执行完成")
执行流程:
┌─────────────────────────────────────┐
│ 线程状态 │
├─────────────────────────────────────┤
│ [运行] print("开始执行") │
│ ↓ │
│ [阻塞中] ████████████████ (3秒) │ ← 线程完全被占用
│ ↓ │
│ [运行] print("执行完成") │
└─────────────────────────────────────┘
特点:
- ✅ 简单直接,易于理解
- ❌ 阻塞整个线程,线程无法执行其他任务
- ❌ 在异步函数中使用会阻塞事件循环
在异步函数中使用 time.sleep(错误示范)
import asyncio
import time
async def bad_example():
print("任务1开始")
time.sleep(3) # 危险!会阻塞整个事件循环
print("任务1完成")
async def bad_example2():
print("任务2开始")
time.sleep(3) # 危险!会阻塞整个事件循环
print("任务2完成")
async def main():
await asyncio.gather(bad_example(), bad_example2())
asyncio.run(main())
问题:虽然使用了 async/await,但 time.sleep(3) 会阻塞事件循环,导致:
- 两个任务实际上串行执行
- 其他协程无法运行
- 失去了异步编程的优势
2. asyncio.sleep - 非阻塞式延迟
工作原理
import asyncio
async def async_task():
print("开始执行")
await asyncio.sleep(3) # 暂停3秒,但不阻塞事件循环
print("执行完成")
执行流程:
事件循环(Event Loop)
┌──────────────────────────────────────────────┐
│ │
│ 任务1: [运行] → [暂停3秒] → [完成] │
│ ↓ │
│ 任务2: [运行] → [暂停3秒] → [完成]│
│ ↓ │
│ 任务3: [运行] → ... │
│ │
└──────────────────────────────────────────────┘
↓ await 时释放控制权,允许其他任务运行 ↓
特点:
- ✅ 只暂停当前协程
- ✅ 释放控制权给事件循环
- ✅ 其他协程可以在暂停期间执行
- ✅ 实现真正的并发执行
正确的异步使用
import asyncio
async def task1():
print("任务1开始")
await asyncio.sleep(3) # 非阻塞暂停
print("任务1完成")
async def task2():
print("任务2开始")
await asyncio.sleep(3) # 非阻塞暂停
print("任务2完成")
async def main():
# 并发执行两个任务
await asyncio.gather(task1(), task2())
asyncio.run(main())
输出:
任务1开始
任务2开始
(等待3秒,两个任务同时暂停)
任务1完成
任务2完成
总耗时:约3秒(而非6秒),因为两个任务并发执行!
3. 实际对比测试
测试代码
import asyncio
import time
import threading
# ========== 使用 time.sleep ==========
def sync_task(name, delay):
print(f"[{name}] 开始 - 线程: {threading.current_thread().ident}")
time.sleep(delay)
print(f"[{name}] 完成 - 耗时: {delay}秒")
def run_sync():
print("\n=== 同步版本 (使用 time.sleep) ===")
start = time.time()
# 顺序执行
sync_task("任务1", 2)
sync_task("任务2", 2)
sync_task("任务3", 2)
print(f"总耗时: {time.time() - start:.2f}秒")
# ========== 使用 asyncio.sleep ==========
async def async_task(name, delay):
print(f"[{name}] 开始 - 线程: {threading.current_thread().ident}")
await asyncio.sleep(delay)
print(f"[{name}] 完成 - 耗时: {delay}秒")
async def run_async():
print("\n=== 异步版本 (使用 asyncio.sleep) ===")
start = time.time()
# 并发执行
await asyncio.gather(
async_task("任务1", 2),
async_task("任务2", 2),
async_task("任务3", 2)
)
print(f"总耗时: {time.time() - start:.2f}秒")
if __name__ == "__main__":
run_sync()
asyncio.run(run_async())
输出结果
=== 同步版本 (使用 time.sleep) ===
[任务1] 开始 - 线程: 12345
[任务1] 完成 - 耗时: 2秒
[任务2] 开始 - 线程: 12345
[任务2] 完成 - 耗时: 2秒
[任务3] 开始 - 线程: 12345
[任务3] 完成 - 耗时: 2秒
总耗时: 6.00秒
=== 异步版本 (使用 asyncio.sleep) ===
[任务1] 开始 - 线程: 12345
[任务2] 开始 - 线程: 12345
[任务3] 开始 - 线程: 12345
(等待2秒...)
[任务1] 完成 - 耗时: 2秒
[任务2] 完成 - 耗时: 2秒
[任务3] 完成 - 耗时: 2秒
总耗时: 2.00秒
性能对比:
- 同步版本:6秒(串行执行)
- 异步版本:2秒(并发执行)
- 性能提升:3倍!
4. FastAPI 中的实际应用
错误示例:在 async 路由中使用 time.sleep
from fastapi import FastAPI
import time
import asyncio
app = FastAPI()
@app.get("/bad")
async def bad_endpoint():
# ❌ 错误!阻塞事件循环
time.sleep(5)
return {"message": "这会阻塞整个服务器5秒!"}
后果:
- 该路由执行期间,其他所有请求都会被阻塞
- 服务器吞吐量急剧下降
- 失去FastAPI的异步优势
正确示例:使用 asyncio.sleep
from fastapi import FastAPI
import asyncio
app = FastAPI()
@app.get("/good")
async def good_endpoint():
# ✅ 正确!非阻塞暂停
await asyncio.sleep(5)
return {"message": "这不会阻塞其他请求"}
优势:
- 该路由暂停期间,其他请求可以正常处理
- 服务器可以同时处理多个请求
- 充分发挥FastAPI的异步性能
混合使用:同步路由用 time.sleep
@app.get("/sync-route")
def sync_route():
# ✅ 在同步函数中使用 time.sleep 是合理的
# FastAPI会在线程池中执行,不会阻塞事件循环
time.sleep(5)
return {"message": "在线程池中执行"}
5. 选择指南
何时使用 time.sleep
# ✅ 适用场景
def main():
# 1. 普通同步脚本
time.sleep(1)
# 2. 多线程程序(每个线程独立)
def worker():
time.sleep(1)
# 3. 同步路由(FastAPI会在线程池中执行)
@app.get("/sync")
def sync_route():
time.sleep(1)
return {"ok": True}
何时使用 asyncio.sleep
# ✅ 适用场景
async def main():
# 1. 异步协程中
await asyncio.sleep(1)
# 2. 需要并发执行多个IO任务
await asyncio.gather(
asyncio.sleep(1),
asyncio.sleep(2),
)
# 3. 异步路由
@app.get("/async")
async def async_route():
await asyncio.sleep(1)
return {"ok": True}
6. 常见错误
错误1:忘记 await
async def wrong():
asyncio.sleep(3) # ❌ 忘记 await,不会暂停!
print("这会立即执行")
async def correct():
await asyncio.sleep(3) # ✅ 正确
print("这会在3秒后执行")
错误2:在异步函数中混用 time.sleep
async def mixed():
print("开始")
await asyncio.sleep(1) # ✅ 非阻塞
time.sleep(1) # ❌ 阻塞事件循环!
await asyncio.sleep(1) # ✅ 非阻塞
print("完成")
错误3:在同步函数中尝试 await
def wrong():
# ❌ 错误!同步函数不能使用 await
await asyncio.sleep(1)
# 正确做法1:改用 async def
async def correct1():
await asyncio.sleep(1)
# 正确做法2:使用 asyncio.run
def correct2():
asyncio.run(asyncio.sleep(1))
7. 性能对比总结
串行执行 vs 并发执行
串行执行 (time.sleep):
任务1: [████████] 2秒
任务2: [████████] 2秒
任务3: [████████] 2秒
总耗时: 6秒
并发执行 (asyncio.sleep):
任务1: [████████]
任务2: [████████] 同时执行
任务3: [████████]
总耗时: 2秒
适用场景对比
| 场景 | 推荐函数 | 原因 |
|---|---|---|
| 简单脚本延迟 | time.sleep |
简单直接 |
| 异步API开发 | asyncio.sleep |
不阻塞事件循环 |
| 同步API路由 | time.sleep |
在线程池执行,安全 |
| 异步IO密集任务 | asyncio.sleep |
高并发性能 |
| CPU密集计算 | 多进程 | 不适用sleep |

浙公网安备 33010602011771号