如何在线程完成时更改 Flask 中呈现的模板?

How do I change the rendered template in Flask when a thread completes?

我有一个功能可以在网络上抓取数据并计算搜索得分。但是,这可能需要一段时间,有时网页会在完成执行前超时。

所以我创建了一个单独的线程来执行该函数,loading.html 告诉客户端数据仍在收集中。一旦函数在线程中结束,我如何重新加载网页以显示显示分数的 output.html

这是我目前拥有的一个更简单的版本:

from flask import Flask
from flask import render_template
from threading import Thread

app = Flask(__name__)

@app.route("/")
def init():
    return render_template('index.html')

@app.route("/", methods=['POST'])
def load():
    th = Thread(target=something, args=())
    th.start()
    return render_template('loading.html')

def something():
    #do some calculation and return the needed value

if __name__ == "__main__":
    app.run()

如何在线程 th 内的 something() 完成后将我的应用程序路由到 render_template('output.html', x=score)

我想避免像 redis 这样的任务队列,因为我想在网络上部署这个应用程序并且我不想产生费用(这更多是一种实验和爱好)。

由于我是 flask 和多线程的新手,所以详细的代码答案会有很大帮助

一种简单的方法是向 thread_status 端点发出循环 Ajax 请求,该端点为您提供有关当前 运行ning 任务的信息。

import time
from flask import Flask, jsonify
from flask import render_template
from threading import Thread

app = Flask(__name__)
th = Thread()
finished = False


@app.route("/")
def init():
    return render_template('index.html')


@app.route("/", methods=['POST'])
def load():
    global th
    global finished
    finished = False
    th = Thread(target=something, args=())
    th.start()
    return render_template('loading.html')


def something():
    """ The worker function """
    global finished
    time.sleep(5)
    finished = True


@app.route('/result')
def result():
    """ Just give back the result of your heavy work """
    return 'Done'


@app.route('/status')
def thread_status():
    """ Return the status of the worker thread """
    return jsonify(dict(status=('finished' if finished else 'running')))


if __name__ == "__main__":
    app.run(debug=True)

所以在你的 loading.html 中插入一个循环 Ajax get() 请求:

<html>
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
    <script>
      $(document).ready(function() {
        var refresh_id = setInterval(function() {
            $.get(
              "{{ url_for('thread_status') }}",
              function(data) {
                console.log(data);
                if (data.status == 'finished') {
                  window.location.replace("{{ url_for('result') }}");
                }
              }
            )}
          , 1000);
      });
    </script>
  </head>
  <body>
    <p>Loading...</p>
  </body>
</html>

如果愿意,您甚至可以通过进度计数器附加它。但是您需要注意防止线程多次 运行。