You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI中asyncio.create_task未后台运行异步方法的问题

问题原因

你的代码里update_materialized_view是同步阻塞函数,里面的数据库操作(调用存储过程、查询视图更新时间)都是阻塞式的。在异步函数_semaphore_update_mview_rasa_family_list中直接调用这个同步函数时,会占用FastAPI的异步事件循环线程,导致整个事件循环被卡住——即使你用loop.create_task把任务丢到后台,事件循环也得等这个同步任务执行完才能处理接口的返回逻辑,所以接口无法立即返回transaction_id。

解决方法

核心思路是把同步阻塞的数据库操作从事件循环线程中剥离,避免阻塞事件循环。最简便的方案是用asyncio.to_thread将同步函数放到线程池执行,这样事件循环可以继续处理其他请求(包括当前接口的返回)。

修改后的代码示例

import asyncio
from uuid import uuid4
from fastapi import FastAPI
# 假设其他依赖(get_db_session、log_file_and_shelve等)已正确导入

semaphore_update_mview_rasa_family_list = asyncio.Semaphore(1)
app = FastAPI()

def update_materialized_view(id_=str(uuid4())):
    log_file_and_shelve(id_=id_, message="update_materialized_view started updating mview")
    session, engine = get_db_session()
    session.execute(text("CALL dbms_mview.refresh(:mview)"), params={"mview": 'MVIEW_RASA_FAMILY_LIST'})
    session.close()
    q = last_mat_view_update_time()
    log_file_and_shelve(id_=id_, message=f"update_materialized_view finished updating mview {q}")
    return q

def last_mat_view_update_time():
    session, engine = get_db_session()
    q = session.execute(text("""
    SELECT to_char(LAST_REFRESH_DATE, 'yyyymmdd hh24:mi:ss', 'nls_calendar=persian') j_LAST_REFRESH_DATE, 
    to_char(LAST_REFRESH_END_TIME, 'yyyymmdd hh24:mi:ss', 'nls_calendar=persian') j_LAST_REFRESH_END_TIME,
    LAST_REFRESH_DATE, LAST_REFRESH_END_TIME
    FROM USER_MVIEWS
    WHERE MVIEW_NAME = 'MVIEW_RASA_FAMILY_LIST'
    """)).fetchone()
    session.close()
    return list(q)

async def _semaphore_update_mview_rasa_family_list(id_=str(uuid4())):
    async with semaphore_update_mview_rasa_family_list:
        # 用to_thread把同步函数丢到线程池执行,不阻塞事件循环
        await asyncio.to_thread(update_materialized_view, id_=id_)
        await asyncio.sleep(1)

@app.get("/update-mat-view", tags=['Database Service', 'Update Database'])
async def update_mview_rasa_family_list():
    id_ = str(uuid4())
    asyncio.create_task(_semaphore_update_mview_rasa_family_list(id_=id_))
    # 直接用asyncio.create_task即可,无需手动获取事件循环
    return {"transaction_id": id_}

关键改动说明

  • 把update_materialized_view(id_=id_)替换为await asyncio.to_thread(update_materialized_view, id_=id_):to_thread会将同步函数提交到线程池执行,异步等待结果,期间事件循环可以正常处理其他任务(比如当前接口的返回)。
  • 简化任务创建:直接用asyncio.create_task即可,FastAPI的异步环境下会自动使用当前事件循环,无需手动获取。

进阶优化(可选)

如果希望彻底异步化,可以改用异步数据库驱动(比如Oracle的oracledb异步模式、PostgreSQL的asyncpg),将get_db_session、session.execute等操作改成异步方法,整个流程会完全非阻塞,性能更优,但需要调整数据库操作的相关代码。

内容的提问来源于stack exchange,提问作者Saeb Molaee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 22:42:48