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补丁解决冲突:
- 安装依赖:
pip install nest-asyncio - 在代码入口处添加补丁:
import nest_asyncio nest_asyncio.apply()
方案2:使用Dash原生后台回调(官方推荐,适合耗时较长的拉取场景)
Dash 2.6及以上版本支持long_callback(后台回调),原生支持异步函数定义,不需要做异步转同步的适配。
- 首先安装依赖:
pip install diskcache dash[diskcache] - 初始化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)
- 将原同步回调改为异步后台回调:
@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
相关产品推荐
相关产品推荐

