Python Flask在同时执行函数的同时返回html页面

Zac*_*ach 6 python flask

我目前正在创建使用Python瓶一个web应用程序,我碰到的一个路障,我不知道如果我甚至想它正确.

因此,我网站的主页只是一个简单的登录页面,其中包含执行网站功能所需的文本输入.我想要实现的是Web应用程序在输入文本后执行两项操作.首先,服务器获取用户名输入并执行一个不向用户返回任何内容的函数,但会创建一堆数据,这些数据将记录到sqlite数据库中,并在稍后的过程中使用.然后,服务器返回在输入用户名后必须进行的调查的网页.但是,服务器执行的功能可能需要2分钟以上,具体取决于用户.我目前对其编码的方式,服务器执行该功能,然后一旦完成,它返回网页,因此用户卡在加载屏幕上最多2分钟.

@app.route("/survey")
def main(raw_user):
    raw_user = request.args.get("SteamID")      <
    games = createGameDict(user_obj)            <----- the function
    tag_lst = get_tags(games)                   <
    return render_template("survey_page.html")
Run Code Online (Sandbox Code Playgroud)

由于调查不依赖于用户输入,而是让用户坐在加载屏幕上,我希望他们能够在功能在后台运行时开始调查,这是可能的,我将如何去做?

dav*_*ing 7

更新:我必须在Flask中多次解决这个问题,所以我写了一个名为Flask-Executor的小型Flask扩展程序来为我完成.它是concurrent.futures的包装器,提供了一些方便的功能,是我处理不需要在Flask中分发的后台任务的首选方式.


对于更复杂的背景任务,像芹菜这样的东西是你最好的选择.但是,对于更简单的用例,您需要的是threading模块.

请考虑以下示例:

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()
Run Code Online (Sandbox Code Playgroud)

在这里,我们创建一个函数,slow_function()在返回之前休眠五秒钟.当我们在路由函数中调用它时,它会阻止页面加载.运行该示例并在浏览器中点击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()
Run Code Online (Sandbox Code Playgroud)

我们在这里做的很简单.我们正在创建一个新实例,Thread并将它传递给它两件事:target我们想要运行的函数,以及args要传递给目标函数的参数.请注意,没有括号slow_function,因为我们没有运行它 - 函数是对象,所以我们将函数本身传递给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()
Run Code Online (Sandbox Code Playgroud)

async_slow_function()功能正在完成我们之前正在做的事情 - 它现在只是有点整洁.您可以在任何路径中调用它,而无需重新编写线程逻辑.你会发现,这个函数实际上返回线程-我们并不需要针对这个例子,但也有可能是您想用该线程以后做其他的事情,所以返回它使线程对象可用,如果你需要它.