当前位置: 首页 > news >正文

Flask应用中处理异步事件(后台线程+事件循环)的方法

在进行flask应用开发的时候遇到这样的一个问题:

在主线程之外需要一个异步处理的事件,需要反复启动和运行该函数(事件)

现在做一个比喻来理解这个问题

Flask主线程:是厨房的主厨。他负责接待所有顾客的点单(HTTP请求),并且快速地处理一些简单的菜,比如做个沙拉(返回静态页面)。他非常忙,必须马上响应下一个顾客,不能被一道菜卡住。

某一个函数:这是一道非常复杂的“佛跳墙”。它需要启动一个子进程(点燃一个新的炉子)、和炉子上的锅(服务器)来回沟通好几次。做这道菜要花很长时间。

为了解决这个问题,我们雇佣了一位副厨,并给了他一个专用的炉子。主厨以后接到“佛跳墙”的订单,就直接交给副厨去做。

首先,需要购买一个新的炉子(新的进程)

background_loop = asyncio.new_event_loop()

然后,需要写一份说明书

def start_event_loop(loop: asyncio.AbstractEventLoop):"""在一个线程中启动并永远运行事件循环"""# a. 将当前线程的事件循环设置为我们传入的那个loop对象asyncio.set_event_loop(loop)# b. 启动事件循环,并让它永远运行下去,等待任务。loop.run_forever()
  • asyncio.set_event_loop(loop):“到岗后,请认准分配给你的那个炉子(loop),以后你只用它。” (这确保了副厨不会和主厨抢炉子用)
  • oop.run_forever():“点燃你的炉子,然后就守在旁边,永远不要离开。随时准备接收任务。” (这就是让炉子一直“运行中”的关键)

正式雇佣副厨,让他上岗工作

# 创建一个全局的事件循环和后台线程
loop_thread = threading.Thread(target=start_event_loop,  # 告诉副厨,你的工作内容是那份“岗位说明书”args=(background_loop,),   # 把“专用的新炉子”交给他daemon=True               # 告诉他,如果主厨下班了,你也跟着下班
)
loop_thread.start() # 命令副厨:“开始工作!”
  • threading.Thread: 我们从人才市场(threading库)找到了一个人,准备让他成为我们的新员工 (loop_thread)。
  • target=start_event_loop: 我们把“岗位说明书”交给了他。
  • args=(background_loop,): 我们把“专用的新炉子”指派给了他。
  • daemon=True: 这是一个重要的雇佣条款。意思是“你是一个临时工,只要我这个主厨(主程序)下班关店了,你就可以立刻下班,不用管手里的活干完没”。这能防止主程序退出后,后台线程还在运行的尴尬情况。
  • loop_thread.start(): 主厨一声令下,副厨立刻跑到他的炉子边,按照岗位说明书的要求,点火并永远地守在那里了。

那么应该怎么使用呢:举例:

def handle_message():# ...# a. 把 “做佛跳墙” (ai_call) 这个任务,安全地提交给副厨的炉子future = asyncio.run_coroutine_threadsafe(ai_call(user_input), background_loop)# b. 主厨在这里拿着“取餐单”(future),等待副厨完成。response = future.result() 
  • 语法 asyncio.run_coroutine_threadsafe(...):
  • 比喻:这是主厨的一个特殊技能,叫做“线程安全的任务交接”。他把“佛跳墙的菜谱”(ai_call(user_input)),贴在了副厨的炉子(background_loop)上,并拿到了一张取餐单(future)。
  • 语法 future.result():
  • 比喻:主厨拿着这张取餐单,就在出餐口等着。他自己不干活,就只是等待。这个等待是阻塞的,但他只阻塞了“上这一道菜”这个行为,他随时可以被其他事情打断(尽管在Flask里他还是会等完)。一旦副厨把菜做好了放在出餐口,future.result() 就立刻拿到了这道菜(response),主厨就可以把它端给客人了。

相关文章:

  • 达梦数据库 单机部署dmhs同步复制(DM8—>DM8)
  • 高频面试之6Hive
  • Redis: List类型
  • Redis免费客户端工具推荐
  • Github月度新锐热门工具 - 202506
  • [HarmonyOSNext鸿蒙开发]11.ArkUI框架:Swiper、Grid布局与代码复用实战指南
  • Spring Boot 集成 Redis 实战教程
  • spring boot源码和lib分开打包
  • AWS CloudFormation实战:构建可复用的ECS服务部署模板
  • AWS TAM行为面试模拟题
  • onnx 模型转 rknn 部署 rk3588 开发板
  • Centos与RockLinux设置静态ip
  • TripGenie:畅游济南旅行规划助手:团队工作纪实(十四)
  • 26-Oracle 23 ai Automatic Transaction Rollback(行锁终结者)
  • 如何正确的用Trae 打开 Unity 3D 项目
  • 神经网络全景图:五大核心架构详解与本质区别
  • QB/T 8103-2024 氯化聚氯乙烯板材检测
  • java并发包中的ReentrantLock锁详解篇
  • Java Collection接口解析
  • C++与C有什么不同