如果你在Flask中启动过子线程,然后在子线程中读写过g
对象或者尝试从request
对象中读取url参数,那么,你肯定对下面这个报错不陌生:RuntimeError: Working outside of request context.
.
例如下面这段Flask代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import threading from flask import Flask, request
app = Flask(__name__)
def inner_func(): doc_id = request.args.get('doc_id', '') print(f'用户ID为:{doc_id}')
@app.route('/start_thread') def start_thread(): thread = threading.Thread(target=inner_func) thread.start() return {'success': True, 'msg': '获取用户ID成功!'}
|
请求/start_thread
接口就会报错,如下图所示:
如果你在网上搜索flask thread RuntimeError: Working outside of request context.
,那么你可能会看到官方文档或者StackOverFlow上面提供了一个装饰器@copy_current_request_context
。如下图所示:
照着它这样写,确实能解决问题,如下图所示:
但无论是官网还是StackOverFlow,它的例子都非常简单。但是我们知道,启动线程有很多种方法,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import threading
job = threading.Thread(target=函数名, args=(参数1, 参数2), kwargs={'参数3': xxx, '参数4': yyy}) job.start()
import threading
class Job(threading.Thread): def __init__(self, 参数): super().__init__() def run(self): print('子线程开始运行')
job = Job(参数) job.start()
from multiprocessing.dummy import Pool pool = Pool(5) pool.map(函数名, 参数列表)
|
网上的方法只能解决第一种写法的问题。如果想使用方法2和方法3启动子线程,代码应该怎么写呢?如果在子线程中又启动子线程,再用一次@copy_current_request_context
还行吗?
相信我,你在网上搜索一下午,只有两种结果:一是找不到答案,二是找到的答案是晚于2023年1月14日的,因为是别人看了我这篇文章以后,再写的。