【问题标题】:How do I change the rendered template in Flask when a thread completes?线程完成后,如何在 Flask 中更改渲染的模板?
【发布时间】:2016-12-25 06:44:23
【问题描述】:

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

所以我创建了一个单独的线程来执行该函数和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()

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

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

因为我是烧瓶和多线程的新手,所以用代码详细回答会有很大帮助

【问题讨论】:

    标签: python multithreading heroku flask backgroundworker


    【解决方案1】:

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

    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>
    

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

    【讨论】:

    • 这就像我想要的那样工作!谢谢!想知道为什么我之前没想过写一个 javascript 函数
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-14
    • 1970-01-01
    • 2014-07-14
    • 1970-01-01
    相关资源
    最近更新 更多