Prompts-MCP 686 skills · ai / design / design-pattern / framework / fundamentals / habit / lang / tech-selection /mcp/sse
lang lang/python/async/no-blocking-call.md medium

python-no-blocking-call

async 函数内禁用同步阻塞 I/O — 一个阻塞调用拖死整个 event loop。Use when 写 Python 后端代码 / 评审涉及 `no-blocking-call` 的 PR。

asyncawaitasyncioblockingsleeprequests函数内禁数内禁用内禁用同
paths
  • backend/**/*.py
  • py/**/*.py

Python · 禁同步阻塞调用

规则

async def 函数内禁止任何同步阻塞 I/O。否则一个调用就能阻塞整个 event loop,所有并发任务全卡。

必须替换的常见同步调用

同步(禁用) 异步(必须替换为)
time.sleep(s) await asyncio.sleep(s)
requests.get(url) await httpx.AsyncClient().get(url)aiohttp
redis.Redis().get(k) await redis.asyncio.Redis().get(k)
同步 SQL 客户端 Tortoise / SQLAlchemy async / asyncpg
open(path).read() 大文件 await aiofiles.open(path).read()
subprocess.run(cmd) await asyncio.create_subprocess_exec(...)

检测方法

# 仓库内 grep 出可疑同步调用
grep -RIn --include="*.py" -E "^[^#]*\b(time\.sleep|requests\.(get|post|put|delete)|open\(.+\)\.read)\b" backend/ py/

CI 可以集成这一步,命中即 fail。

反例 → 正例

# ❌ async 内调 requests(拉死 event loop)
async def fetch_textbook(tid: int):
    resp = requests.get(f"http://textbook/{tid}")  # blocking!
    return resp.json()

# ✅ 用 httpx async
async def fetch_textbook(tid: int):
    async with httpx.AsyncClient() as client:
        resp = await client.get(f"http://textbook/{tid}")
        return resp.json()
# ❌ async 内 time.sleep
async def retry_with_backoff():
    for i in range(3):
        try:
            return await do_work()
        except Exception:
            time.sleep(2 ** i)   # blocking!

# ✅ asyncio.sleep
async def retry_with_backoff():
    for i in range(3):
        try:
            return await do_work()
        except Exception:
            await asyncio.sleep(2 ** i)

例外:CPU 密集型计算

CPU 密集型操作(图像处理、PDF 渲染、大数据处理)不算 I/O 阻塞,但仍会卡 loop。 用 asyncio.to_threadloop.run_in_executor 丢到线程池:

result = await asyncio.to_thread(pillow_resize, image_data, 800, 600)

或丢到 RQ worker(workers/ 目录)异步处理,主路由立即返回 task_id。

自检

  • [ ] async 函数内没有 time.sleep / requests.* / 同步 redis?
  • [ ] 大文件 / CPU 密集型走 to_thread 或 RQ worker?
  • [ ] 第三方库选了 async 版本?(httpx / redis.asyncio / aiofiles)

相关