如何让 Flask/Gunicorn 处理同一路由的并发请求?
How to get Flask/Gunicorn to handle concurrent requests for the same Route?
tl;dr 用 route
修饰的方法无法处理并发请求,而 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.
tl;dr 用 route
修饰的方法无法处理并发请求,而 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.