更新:我不得不在 Flask 中多次解决这个问题,所以我编写了一个名为的小型 Flask 扩展Flask执行器 https://github.com/dchevell/flask-executor为我做这件事。它是并发的包装器,提供了一些方便的功能,并且是我处理不需要在 Flask 中分发的后台任务的首选方法。
对于更复杂的后台任务,像芹菜这样的东西是你最好的选择。然而,对于更简单的用例,您想要的是threading
module.
考虑以下示例:
from flask import Flask
from time import sleep
app = Flask(__name__)
def slow_function(some_object):
sleep(5)
print(some_object)
@app.route('/')
def index():
some_object = 'This is a test'
slow_function(some_object)
return 'hello'
if __name__ == '__main__':
app.run()
在这里,我们创建一个函数,slow_function()
返回之前会休眠五秒钟。当我们在路由函数中调用它时,它会阻止页面加载。运行示例并点击http://127.0.0.1:5000 http://127.0.0.1:5000在浏览器中,您将看到页面在加载前等待五秒钟,然后在终端中打印测试消息。
我们想做的是把slow_function()
在不同的线程上。只需添加几行代码,我们就可以使用threading
模块将该函数的执行分离到不同的线程上:
from flask import Flask
from time import sleep
from threading import Thread
app = Flask(__name__)
def slow_function(some_object):
sleep(5)
print(some_object)
@app.route('/')
def index():
some_object = 'This is a test'
thr = Thread(target=slow_function, args=[some_object])
thr.start()
return 'hello'
if __name__ == '__main__':
app.run()
我们在这里做的事情很简单。我们正在创建一个新实例Thread
并传递两件事:target
,这是我们要运行的函数,并且args
,要传递给目标函数的参数。注意,上面没有括号slow_function
,因为我们不是runningit - 函数是对象,所以我们传递函数itself to Thread
。至于args
,这总是需要一个列表。即使您只有一个参数,也请将其包装在一个列表中,以便args
得到它所期望的。
当我们的线程准备就绪时,thr.start()
执行它。在浏览器中运行此示例,您会注意到索引路由现在立即加载。但再等五秒钟,果然,测试消息将打印在您的终端中。
现在,我们可以在这里停下来 - 但至少在我看来,在路由本身内部实际包含此线程代码有点混乱。如果您需要在另一个路由或不同的上下文中调用此函数怎么办?最好将其分离为自己的功能。您可以使线程行为成为慢速函数本身的一部分,或者您可以创建一个“包装”函数 - 您采用哪种方法在很大程度上取决于您正在做什么以及您的需求是什么。
让我们创建一个包装函数,看看它是什么样子的:
from flask import Flask
from time import sleep
from threading import Thread
app = Flask(__name__)
def slow_function(some_object):
sleep(5)
print(some_object)
def async_slow_function(some_object):
thr = Thread(target=slow_function, args=[some_object])
thr.start()
return thr
@app.route('/')
def index():
some_object = 'This is a test'
async_slow_function(some_object)
return 'hello'
if __name__ == '__main__':
app.run()
The async_slow_function()
函数所做的事情几乎与我们之前所做的完全一样 - 现在只是更简洁了一些。您可以在任何路由中调用它,而无需重新重写线程逻辑。您会注意到这个函数实际上返回线程 - 我们没有need对于本例来说是这样,但是稍后您可能想对该线程执行其他操作,因此返回它可以使线程对象在您需要时可用。