简体   繁体   English

使用Flask和eventlet响应并发请求

[英]Responding to concurrent requests with Flask and eventlet

I try to set up a minimal Flask application that uses eventlet to respond to concurrent requests instantly instead of blocking and responding to one request after the other (as the standard Flask debugging webserver does). 我尝试设置一个最小的Flask应用程序,该应用程序使用eventlet立即响应并发请求,而不是阻塞并响应一个请求(如标准的Flask调试Web服务器那样)。

Prerequisites: 先决条件:

pip install Flask
pip install eventlet

From my understanding by what I found so far on the internet, it should work like this: 从我到目前为止在互联网上发现的东西的理解,它应该像这样工作:

# activate eventlet
import eventlet
eventlet.monkey_patch()

from flask import Flask

import datetime
from time import sleep

# create a new Flask application
app = Flask(__name__)

# a short running task that returns immediately
@app.route('/shortTask')
def short_running_task():
  start = datetime.datetime.now()
  return 'Started at {0}, returned at {1}'.format(start, datetime.datetime.now())

# a long running tasks that returns after 30s
@app.route('/longTask')
def long_running_task():
  start = datetime.datetime.now()
  sleep(30)
  return 'Started at {0}, returned at {1}'.format(start, datetime.datetime.now())

# run the webserver
if __name__ == '__main__':
    app.run(debug=True)

When running this file, then opening http://localhost:5000/longTask in a webbrowser tab and while it is still processing opening another tab with http://localhost:5000/shortTask , I would expect the second tab to return immediately while the first tab is still loading. 运行此文件时,然后在webbrowser选项卡中打开http://localhost:5000/longTask ,当它仍在处理打开另一个带有http://localhost:5000/shortTask的选项卡时,我希望第二个选项卡能够立即返回第一个标签仍在加载。 However, similar to when running this on the standard Werkzeug server, the second tab only returns just after the first one is finished after 30s. 但是,与在标准Werkzeug服务器上运行此类似时,第二个选项卡仅在第一个选项卡在30秒后完成后才返回。

What is wrong here? 这有什么不对? By the way, would this be what is commonly referred to as a "production ready webserver" for Flask, given that there are only few concurrent users to be expected (5 at most)? 那么,对于Flask来说,这通常被称为“生产就绪的网络服务器”,假设只有很少的并发用户(最多5个)?

By the way, when I use the Flask-socketio library to run the webserver which, according to the documentation, automatically chooses eventlet if it is installed, then it works as expected. 顺便说一句,当我使用Flask-socketio库运行web服务器时,根据文档,如果安装了eventlet,它会自动选择eventlet,然后按预期工作。

Complete example with Flask-socketio: Flask-socketio的完整示例:

# activate eventlet
import eventlet
eventlet.monkey_patch()

from flask import Flask
from flask_socketio import SocketIO

import datetime
from time import sleep

# create a new Flask application
app = Flask(__name__)

# activate Flask-socketio
socketio = SocketIO(app)

# a short running task that returns immediately
@app.route('/shortTask')
def short_running_task():
  start = datetime.datetime.now()
  return 'Started at {0}, returned at {1}'.format(start, datetime.datetime.now())

# a long running tasks that returns after 30s
@app.route('/longTask')
def long_running_task():
  start = datetime.datetime.now()
  sleep(30)
  return 'Started at {0}, returned at {1}'.format(start, datetime.datetime.now())

# run the webserver with socketio
if __name__ == '__main__':
    socketio.run(app, debug=True)

When you run app.run(debug=True) you are explicitly telling Flask to run your application on the development web server, which is based on Werkzeug. 当您运行app.run(debug=True)您明确告诉Flask在开发Web服务器上运行您的应用程序,该服务器基于Werkzeug。 It does not matter that you have loaded eventlet. 加载eventlet没关系。

If you want to run your application on the eventlet web server, you have to start an eventlet web server, which according to the documentation is started as follows: 如果要在eventlet Web服务器上运行应用程序,则必须启动一个eventlet Web服务器,该服务器根据文档启动如下:

wsgi.server(eventlet.listen(('', 8000)), your_app)

This is more or less what socketio.run() does in my Flask-SocketIO extension, with a little bit more complexity to optionally handle SSL. 这或多或少是socketio.run()在我的Flask-SocketIO扩展中的作用,可选择处理SSL的复杂程度socketio.run() The lines of code that do this are: https://github.com/miguelgrinberg/Flask-SocketIO/blob/539cd158f49ce085151911cb63edbacd0fa37173/flask_socketio/ init .py#L391-L408 . 的代码,做到这一点的线路有: https://github.com/miguelgrinberg/Flask-SocketIO/blob/539cd158f49ce085151911cb63edbacd0fa37173/flask_socketio/ 初始化的.py#L391-L408 If you look around those lines, you will see that there are three different start up chunks of code, one for werkzeug, one for eventlet and one for gevent. 如果你环顾这些行,你会发现有三个不同的启动代码块,一个用于werkzeug,一个用于eventlet,一个用于gevent。 They are all different. 他们都是不同的。

import eventlet
eventlet.monkey_patch()

Won't magically turn your code into a multithread beast that can handle request asynchronously (it is still pretty magical and awesome). 不会神奇地将你的代码变成一个可以异步处理请求的多线程野兽(它仍然非常神奇和令人敬畏)。

As you can see in this example , you need to launch the wsgi server using eventlet wsgi's implementation . 正如您在此示例中所看到的,您需要使用eventlet wsgi的实现来启动wsgi服务器。

If you want a standard solution, have a look at how to use nginx and uwsgi to launch flask application. 如果您需要标准解决方案,请查看如何使用nginx和uwsgi来启动flask应用程序。 You also may be interested in the project Spawning that leverage the pain of creating a complete multithread wsgi handler. 您也可能对Spawning项目感兴趣,该项目利用创建完整的多线程wsgi处理程序的痛苦。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM