如何让 Flask/Gunicorn 处理同一路由的并发请求?

How to get Flask/Gunicorn to handle concurrent requests for the same Route?

tl;drroute 修饰的方法无法处理并发请求,而 Flask 是在一个由多个工作者和线程启动的 gunicorn 后面提供的,而两个不同的方法可以很好地处理并发请求。为什么会这样,同一条路由如何并发服务?


我有这个简单的烧瓶应用程序:

from flask import Flask, jsonify
import time
app = Flask(__name__)

@app.route('/foo')
def foo():
    time.sleep(5)
    return jsonify({'success': True}), 200

@app.route('/bar')
def bar():
    time.sleep(5)
    return jsonify({'success': False}), 200

如果我 运行 通过:

gunicorn test:app -w 1 --threads 1

如果我在浏览器的两个不同选项卡中快速打开 /bar/foo,我首先按回车键的选项卡将在 5 秒内加载,第二个选项卡将在 10 秒内加载秒。这是有道理的,因为 gunicorn 运行一个线程一个工人。

如果我 运行 通过以下任一方式:

gunicorn test:app -w 1 --threads 2
gunicorn test:app -w 2 --threads 1

在这种情况下,在两个不同的选项卡中打开 /foo/bar 都需要 5 秒。这是有道理的,因为 gunicorn 运行要么是 1 个 worker 有两个线程,要么是两个 worker 每个有一个线程,并且可以同时为两条路线提供服务。

但是,如果我同时打开两个/foo,无论gunicorn配置如何,第二个标签总是需要10秒。

如何获得由 route 装饰的相同方法来处理并发请求?

这个问题应该不是Gunicorn或Flask引起的,而是浏览器引起的。 我只是试图重现它。它有两个 Firefox 标签页;但是,如果我 运行 两个 curl 进程在不同的控制台中,那么它们将按预期(并行)得到服务,并且它们的请求由不同的工作人员处理 - 这可以通过启用 --log-level DEBUG 来检查,而开始 gunicorn.

我认为这是因为 Firefox(可能还有其他浏览器)为每个 URL 打开到服务器的单个连接;当您在两个选项卡上打开一个页面时,它们的请求将通过相同的 (kept-alive) 连接发送,因此会到达同一个工作人员。

因此,即使使用像 eventlet 这样的异步 worker 也无济于事:异步 worker 可能一次处理多个 connections,但是当两个请求到达相同的连接,那么它们必然会被处理 one-by-one.