Python Django中ThreadPoolExecutor如何让主线程等待所有任务完成
解决Django视图中多线程并行执行存储过程后主线程等待问题
现有代码核心问题
- 主线程未等待子线程执行完成就直接返回,导致
context还未被赋值就传给模板 submit调用时参数顺序错误:resultados_proceso和resultadosGrafica_proceso的第一个参数是context,但原代码未传入,会引发参数匹配异常
修正方案一:使用shutdown(wait=True)等待所有任务完成
from concurrent.futures import ThreadPoolExecutor def resultados(request): context = {} # 整理任务与对应参数 task_list = [ (resultados_proceso, (context, regiones, territorios, canales, marcas, periodos)), (resultadosGrafica_proceso, (context, regiones, territorios, canales, marcas, periodos)), (get_volumen_ejecucion_clientes_iniciativa, (106,)), (get_volumenAP_xmarca, (['M'],)) ] # 用with语句管理线程池,自动处理资源释放 with ThreadPoolExecutor() as executor: for func, args in task_list: executor.submit(func, *args) # 等待所有子线程执行完毕后再继续主线程逻辑 executor.shutdown(wait=True) return render(request, 'resultados.html', context) def resultados_proceso(context, regiones, territorios, canales, marcas, periodos): context['resultados'] = getResultados(regiones, territorios, canales, marcas, periodos) def resultadosGrafica_proceso(context, regiones, territorios, canales, marcas, periodos): context['grafica'] = getResultadosGrafica(regiones, territorios, canales, marcas, periodos)
修正方案二:使用wait()跟踪任务状态(更灵活)
from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED def resultados(request): context = {} executor = ThreadPoolExecutor() futures = [] # 提交任务并保存每个任务的Future对象 futures.append(executor.submit(resultados_proceso, context, regiones, territorios, canales, marcas, periodos)) futures.append(executor.submit(resultadosGrafica_proceso, context, regiones, territorios, canales, marcas, periodos)) futures.append(executor.submit(get_volumen_ejecucion_clientes_iniciativa, 106)) futures.append(executor.submit(get_volumenAP_xmarca, ['M'])) # 等待所有任务完成后再继续 wait(futures, return_when=ALL_COMPLETED) executor.shutdown() return render(request, 'resultados.html', context)
额外注意事项
- 数据库连接处理:Django的数据库连接是线程局部的,子线程执行数据库操作前,建议调用
django.db.close_old_connections()避免复用主线程旧连接,示例:from django.db import close_old_connections def resultados_proceso(context, regiones, territorios, canales, marcas, periodos): close_old_connections() context['resultados'] = getResultados(regiones, territorios, canales, marcas, periodos) - 线程安全:如果有复杂的共享数据操作,建议使用
threading.Lock确保原子性,避免数据异常。
内容的提问来源于stack exchange,提问作者Leonardo Esquivel
相关产品推荐
相关产品推荐

