首页 > 解决方案 > 为什么使用 gunicorn 运行时,线程在 Flask 应用程序中不起作用?

问题描述

当文件上传到我的烧瓶应用程序时,会生成一个线程 ID。这被前端用于稍后获取文件读取过程的进度详细信息(cert_details 路由)

cert_details 路由使用 tesseract、opencv 等从 PDF 读取数据。这是一个资源密集型过程,可能需要一段时间才能执行

在进程运行时,我希望能够使用进度更新前端(即读入多少文件)。因此,我创建了一个单独的线程,该线程的值“进度”在每次处理文件时都会增加。

该应用程序在没有 gunicorn 的情况下工作,即当 docker 命令是CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0"]

如果我将其更改为使用 gunicorn CMD ["gunicorn","--timeout", “60", "--bind", "0.0.0.0:5000", "app:app"] ,则在文件读取过程完成之前进度条不会更新(这违背了进度条的目的)。

为什么线程不适用于 gunicorn?有没有我必须采取的替代方法,或者它是否与线程饥饿有关?

import threading
from flask import Flask, flash, request, redirect, url_for, jsonify, send_from_directory, send_file
from flask_cors import CORS, cross_origin

app = Flask(__name__)
CORS(app)



class ExportingThread(threading.Thread):
    def __init__(self):
        self.progress = 0
        super().__init__()



exporting_threads = {}

@app.route('/uploads', methods=['POST'])
def upload_file():
    if request.method == 'POST':
        if 'files[]' not in request.files:
            
            return {'status':'File upload unsuccesful'}

        files = request.files.getlist('files[]')

        for file in files:
            if file and allowed_file(file.filename):
                
                filename = secure_filename(file.filename)
                file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            else:
                return {'status':'Non pdf file type uploaded'}   
        global thread_id
        thread_id = random.randint(0, 10000)
        return {'status':'sucessful'}

@app.route('/get_thread_id')
def get_thread():
    global thread_id
    return str(thread_id)

@app.route('/progress', methods=['POST'])
def progress():
    
    data = request.json
   
    thread_id = data['thread_id'] 
  
    global exporting_threads
    if thread_id in exporting_threads:
       return str(exporting_threads[thread_id].progress)
    else:
        return '0'   

@app.route('/cert_details', methods=['POST'])
def get_details():  
  
    data = request.json
   
    if 'filenames' not in data:
        return {'error':'filenames not found'}
    else:

        filenames =data['filenames']

        details =[]

        global exporting_threads
        global thread_id
        
        exporting_threads[thread_id] = ExportingThread()
        exporting_threads[thread_id].start()
        
        for file in filenames:
            #this is the resource intensive process using ocr / opencv
            details.append( get_certficate_details( UPLOAD_FOLDER_LOCATION + file, file ) )
            exporting_threads[thread_id].progress += 1
        
        return jsonify(file_details =  details)

标签: flaskgunicorn

解决方案


推荐阅读