AI项目博客
记录 AI 工程实践与大模型应用

FastAPI & SQLAlchemy 实战(三):Task、gather、超时与取消,并发控制的四个工具

「FastAPI & SQLAlchemy 实战」系列共 10 篇,从协程基础讲到数据库接口。这是第 3 篇。

结论:create_task 负责启动并发,gather 负责等待结果,wait_for 负责超时,cancel 负责取消。四个工具解决协程的四种控制需求。

一、create_task:把协程变成任务

import asyncio

async def my_func(name, delay):
    await asyncio.sleep(delay)
    return f"结果 of {name}"

async def main():
    task1 = asyncio.create_task(my_func("C", 1))
    task2 = asyncio.create_task(my_func("D", 2))
    results = await asyncio.gather(task1, task2)
    print(results)   # ['结果 of C', '结果 of D']

create_task 会立即把协程注册到事件循环,两个任务同时开始;gather 只是等待它们结束。总耗时约 2 秒,不是 3 秒。

二、超时:wait_for

async def slow_task():
    await asyncio.sleep(5)

async def main():
    try:
        await asyncio.wait_for(slow_task(), timeout=2.0)
    except asyncio.TimeoutError:
        print("任务超时")

超时后等待对象会被取消,必须捕获 TimeoutError,否则异常会向上抛。

三、取消:Task.cancel

async def worker():
    try:
        await asyncio.sleep(10)
    except asyncio.CancelledError:
        print("清理资源")
        raise

task = asyncio.create_task(worker())
await asyncio.sleep(1)
task.cancel()
try:
    await task
except asyncio.CancelledError:
    pass

取消不是“立即杀死”,而是给协程一个抛出 CancelledError 的机会;捕获后要做资源清理,再重新抛出。

四、阻塞代码:to_thread

协程里调用 requests.get()、time.sleep()、同步数据库驱动,会阻塞整个事件循环。用 asyncio.to_thread() 把它扔到线程池:

import requests

async def fetch(url):
    response = await asyncio.to_thread(requests.get, url)
    return response.status_code

五、并发请求实战

import aiohttp

async def fetch_url(session, url):
    async with session.get(url) as response:
        await response.text()
        return url

async def main():
    urls = ["https://www.baidu.com", "https://www.bing.com", "https://www.github.com"]
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_url(session, url) for url in urls]
        results = await asyncio.gather(*tasks)
        print(results)

总耗时约等于最慢的那个请求,而不是三个请求相加。

六、常见错误

  • 只 create_task 不 await:顶级协程结束后子任务被取消;
  • 在异步函数里用同步库:事件循环被阻塞,所有请求排队;
  • 取消后不做清理:连接、文件句柄可能泄漏;
  • 不处理 TimeoutError:超时变成 500。

下一篇

协程基础讲完,下一篇进入 Web:WSGI 和 ASGI 的区别,以及 FastAPI 为什么必须配 Uvicorn。

上一篇:async/await 与事件循环 | 下一篇:WSGI 与 ASGI

赞(0)
未经允许不得转载:AI项目博客 » FastAPI & SQLAlchemy 实战(三):Task、gather、超时与取消,并发控制的四个工具

评论 抢沙发

AI项目博客

专注 AI 工程化落地 —— 覆盖智能体、大模型、Java AI 与 Python 的学习笔记,以及 AI 平台的项目实战记录。

关于本站文章归档

登录

找回密码

注册