Python Flask在执行功能的同时返回html页面 [英] Python Flask returning a html page while simultaneously performing a function

查看:218
本文介绍了Python Flask在执行功能的同时返回html页面的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用Python Flask创建一个Web应用程序,遇到了一个障碍,我不确定自己是否在正确地考虑它.

I'm currently creating a web app using Python Flask and I've run into a road block and I'm not sure if I'm even thinking about it correctly.

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

So my website's homepage is just a simple landing page with text input that is required to perform the websites function. What I am trying to accomplish is for the web app to perform two things after the text is input. First, the server takes the username input and performs a function that doesn't return anything to the user but creates a bunch of data that is logged into an sqlite database, and used later on in the process. Then, the server returns the web page for a survey that has to be taken after the username is input. However, the function that the server performs can take upwards of 2 minutes depending on the user. The way I currently have it coded, the server performs the function, then once it has finished, it returns the web page, so the user is stuck at a loading screen for up to 2 minutes.

@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")

由于调查不依赖于用户输入,因此我希望他们能够在后台运行功能的同时启动调查,而不必让用户坐在加载屏幕上.我该怎么办?

Since the survey doesn't depend on the user input, instead of having the user sitting at a loading screen, I would like them to be able to start the survey while the functions works in the background, is that possible, and how would I do that?

推荐答案

更新:我不得不在Flask中解决此问题很多次,所以我写了一个名为

Update: I've had to solve this problem a number of times in Flask, so I wrote a small Flask extension called Flask-Executor to do it for me. It's a wrapper for concurrent.futures that provides a few handy features, and is my preferred way of handling background tasks that don't require distribution in Flask.

对于更复杂的后台任务,诸如芹菜之类的东西是您最好的选择.但是,对于更简单的用例,您需要的是 threading 模块.

For more complex background tasks, something like celery is your best bet. For simpler use cases however, what you want is the 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(),该函数在返回前会休眠五秒钟.当我们在route函数中调用它时,它会阻止页面加载.运行该示例,然后在浏览器中点击 http://127.0.0.1:5000 ,您将看到页面等待五秒钟,然后再加载,然后在您的终端中打印测试消息.

Here, we create a function, slow_function() that sleeps for five seconds before returning. When we call it in our route function it blocks the page load. Run the example and hit http://127.0.0.1:5000 in your browser, and you'll see the page wait five seconds before loading, after which the test message is printed in your terminal.

我们想要做的是将 slow_function()放在另一个线程上.仅需几行代码,我们就可以使用 threading 模块将此函数的执行分离到另一个线程上:

What we want to do is to put slow_function() on a different thread. With just a couple of additional lines of code, we can use the threading module to separate out the execution of this function onto a different thread:

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 上没有括号,因为我们不是在 running 上运行-函数是对象,因此我们要传递函数 itself Thread .至于 args ,这总是需要一个列表.即使您只有一个参数,也可以将其包装在列表中,以便 args 获得期望的结果.

What we're doing here is simple. We're creating a new instance of Thread and passing it two things: the target, which is the function we want to run, and args, the argument(s) to be passed to the target function. Notice that there are no parentheses on slow_function, because we're not running it - functions are objects, so we're passing the function itself to Thread. As for args, this always expects a list. Even if you only have one argument, wrap it in a list so args gets what it's expecting.

在线程准备就绪的情况下, thr.start()将其执行.在浏览器中运行此示例,您会注意到索引路由现在立即加载.但是请再等五秒钟,然后确定会在您的终端上打印测试消息.

With our thread ready to go, thr.start() executes it. Run this example in your browser, and you'll notice that the index route now loads instantly. But wait another five seconds and sure enough, the test message will print in your terminal.

现在,我们可以在这里停止-但至少在我看来,实际上在路由本身内部包含此线程代码有点混乱.如果您需要在其他路由或其他上下文中调用此函数,该怎么办?最好将其分离为自己的功能.您可以使线程行为成为慢速函数本身的一部分,也可以使一个包装器"函数-您采用哪种方法在很大程度上取决于您正在做的事情和您的需求.

Now, we could stop here - but in my opinion at least, it's a bit messy to actually have this threading code inside the route itself. What if you need to call this function in another route, or a different context? Better to separate it out into its own function. You could make threading behaviour a part of slow function itself, or you could make a "wrapper" function - which approach you take depends a lot on what you're doing and what your needs are.

让我们创建一个包装函数,看看它是什么样的:

Let's create a wrapper function, and see what it looks like:

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()

async_slow_function()函数的功能几乎与我们之前所做的完全一样-现在稍微整洁了.您可以在任何路由中调用它,而不必再次重写线程逻辑.您会注意到,该函数实际上返回了线程-在本示例中,我们不需要,但是以后您可能还需要对该线程执行其他操作,因此返回该值会使该线程如果需要,可以使用该对象.

The async_slow_function() function is doing pretty much exactly what we were doing before - it's just a bit neater now. You can call it in any route without having to rewrite your threading logic all over again. You'll notice that this function actually returns the thread - we don't need that for this example, but there are other things you might want to do with that thread later, so returning it makes the thread object available if you ever need it.

这篇关于Python Flask在执行功能的同时返回html页面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆