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

Dash同步回调无法异步化时调用异步函数的解决方案咨询

解决方案

Dash的标准同步回调不支持直接定义为async函数,你可以通过以下几种方案在保留Dash框架的前提下解决异步调用问题:


方案1:asyncio同步包装(最轻量,适合中小型项目)

直接在get_data内部将异步调用转换为同步执行,不需要修改上层回调逻辑。
修改后的get_data代码示例:

import asyncio

def get_data(symbolStr):
    print("Getting AR for", symbolStr)
    # 同步等待异步函数执行完成
    df = asyncio.run(amp.get_data_job(symbolStr))
    return df

注意事项:如果部署环境已经存在运行中的事件循环导致asyncio.run报错,可以安装nest_asyncio补丁解决冲突:

  1. 安装依赖:pip install nest-asyncio
  2. 在代码入口处添加补丁:
import nest_asyncio
nest_asyncio.apply()

方案2:使用Dash原生后台回调(官方推荐,适合耗时较长的拉取场景)

Dash 2.6及以上版本支持long_callback(后台回调),原生支持异步函数定义,不需要做异步转同步的适配。

  1. 首先安装依赖:pip install diskcache dash[diskcache]
  2. 初始化Dash应用时配置后台回调管理器:
import dash
from dash.long_callback import DiskcacheLongCallbackManager
import diskcache

# 初始化本地缓存存储后台任务状态
cache = diskcache.Cache("./dash_task_cache")
long_callback_manager = DiskcacheLongCallbackManager(cache)

# 初始化应用时传入管理器
app = dash.Dash(__name__, long_callback_manager=long_callback_manager)
  1. 将原同步回调改为异步后台回调:
@app.long_callback(
    [dash.dependencies.Output('table', 'data')],
    [dash.dependencies.Input('interval1', 'n_intervals')],
    [dash.dependencies.State('table', 'data')]
)
async def update_interval(n, data):
    allSymbolsDf = pd.DataFrame()

    for symbolStr in symbolsStr:
        # 直接await异步调用
        df = await amp.get_data_job(symbolStr)
        # 原append方法已被pandas弃用,改用concat性能更好
        allSymbolsDf = pd.concat([allSymbolsDf, df])
        # 替换同步sleep为异步sleep,不阻塞事件循环
        await asyncio.sleep(3)
   
    # 原to_dict('rows')已被pandas弃用,改用records
    return [allSymbolsDf.to_dict('records')]

优势:不阻塞Dash主线程,支持添加加载动画、任务取消等交互,适合单次数据拉取耗时超过10秒的场景。


方案3:线程池隔离执行(兼容性最好,适合复杂部署环境)

如果不想修改事件循环配置,可以用线程池将异步调用隔离到独立线程执行,完全避免和Dash主线程的事件循环冲突。
代码示例:

import asyncio
from concurrent.futures import ThreadPoolExecutor

# 初始化全局线程池,可根据拉取并发量调整worker数量
executor = ThreadPoolExecutor(max_workers=4)

def async_to_sync(async_func, *args):
    def run_async():
        # 每个线程独立创建事件循环,避免冲突
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        return loop.run_until_complete(async_func(*args))
    # 提交任务到线程池并同步等待结果
    return executor.submit(run_async).result()

def get_data(symbolStr):
    print("Getting AR for", symbolStr)
    df = async_to_sync(amp.get_data_job, symbolStr)
    return df

上层回调逻辑不需要做任何修改。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 20:24:06