如何获取调用函数的Flask-SocketIO后台任务名称或唯一标识?
解决Flask-SocketIO后台任务标识获取问题
为什么threading.current_thread().name无效?
Flask-SocketIO默认使用eventlet或gevent作为异步引擎,后台任务运行在协程而非原生线程中,因此threading模块无法获取到任务的真实标识,只会返回主线程名称。
方案1:通过调用栈自动获取任务函数名(最优雅,无需修改任务调用)
利用inspect模块获取调用writeToConsole的任务函数名称,直接作为任务标识,无需手动传参:
from flask import Flask from flask_socketio import SocketIO import inspect from datetime import datetime app = Flask(__name__) socketio = SocketIO(app) socketio.start_background_task(myTask1) socketio.start_background_task(myTask2) socketio.start_background_task(myTask3) def myTask1(): while True: writeToConsole("Foo") socketio.sleep(1) def myTask2(): while True: writeToConsole("Bar") socketio.sleep(2) def myTask3(): while True: writeToConsole("Baz") socketio.sleep(3) def writeToConsole(msg): # 获取调用栈,第1层是当前函数,第2层是调用它的任务函数 caller_info = inspect.stack()[1] task_name = caller_info.function # 生成格式化时间戳 time_stamp = datetime.now().strftime("%H:%M:%S") print(f"{time_stamp} - Process {task_name} says: {msg}")
优点:
- 完全无需修改原有任务的调用逻辑
- 直接使用任务函数名作为标识,可读性强
- 调试阶段性能足够,无明显开销
方案2:自定义任务名称(支持灵活命名)
通过包装start_background_task,为每个协程任务设置自定义名称,然后在输出时获取该名称:
基于eventlet的实现:
from flask import Flask from flask_socketio import SocketIO import eventlet from datetime import datetime app = Flask(__name__) socketio = SocketIO(app) def named_background_task(task_name, func, *args, **kwargs): """包装函数,给后台任务协程设置自定义名称""" def wrapper(): current_coro = eventlet.getcurrent() current_coro.name = task_name return func(*args, **kwargs) return socketio.start_background_task(wrapper) # 用包装后的函数启动任务,自定义名称 named_background_task("数据同步任务", myTask1) named_background_task("定时清理任务", myTask2) named_background_task("状态监控任务", myTask3) def myTask1(): while True: writeToConsole("Foo") socketio.sleep(1) def myTask2(): while True: writeToConsole("Bar") socketio.sleep(2) def myTask3(): while True: writeToConsole("Baz") socketio.sleep(3) def writeToConsole(msg): current_coro = eventlet.getcurrent() # 如果协程未设置名称,用协程ID兜底 task_name = current_coro.name or f"Coro-{id(current_coro)}" time_stamp = datetime.now().strftime("%H:%M:%S") print(f"{time_stamp} - Process {task_name} says: {msg}")
基于gevent的实现:
如果你的项目使用gevent作为异步引擎,只需替换协程获取逻辑:
import gevent # 替换named_background_task中的协程设置部分 current_coro = gevent.getcurrent() current_coro.name = task_name # 替换writeToConsole中的协程获取部分 current_coro = gevent.getcurrent()
优点:
- 支持自定义有业务意义的任务名称,可读性更强
- 性能比
inspect方案更优,适合高频调用场景
方案3:切换到线程模式(仅适合非高并发场景)
如果你的项目并发量不高,可以指定async_mode='threading'切换到线程模式,此时threading.current_thread().name即可获取线程标识:
from flask import Flask from flask_socketio import SocketIO import threading from datetime import datetime app = Flask(__name__) # 指定使用线程模式 socketio = SocketIO(app, async_mode='threading') socketio.start_background_task(myTask1) socketio.start_background_task(myTask2) socketio.start_background_task(myTask3) def writeToConsole(msg): task_name = threading.current_thread().name time_stamp = datetime.now().strftime("%H:%M:%S") print(f"{time_stamp} - Process {task_name} says: {msg}") # 任务函数保持不变 ...
注意:
线程模式的并发性能远低于协程模式,仅适合低并发场景。
内容的提问来源于stack exchange,提问作者Aaron
相关产品推荐
相关产品推荐

