12

我尝试设置一个最小的 Flask 应用程序,它使用eventlet来立即响应并发请求,而不是阻塞和响应一个又一个请求(就像标准的 Flask 调试网络服务器所做的那样)。

先决条件:

pip install Flask
pip install eventlet

根据我到目前为止在互联网上发现的内容的理解,它应该像这样工作:

# 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)

运行此文件,然后http://localhost:5000/longTask在 webbrowser 选项卡中打开时,当它仍在处理打开另一个选项卡时http://localhost:5000/shortTask,我希望第二个选项卡在第一个选项卡仍在加载时立即返回。但是,与在标准 Werkzeug 服务器上运行此程序类似,第二个选项卡仅在第一个选项卡在 30 秒后完成后才返回。

这里有什么问题?顺便说一句,鉴于预期只有少数并发用户(最多 5 个),这是否是通常所说的 Flask 的“生产就绪网络服务器”?

顺便说一句,当我使用Flask-socketio 库运行网络服务器时,根据文档,如果安装了它,它会自动选择 eventlet,然后它按预期工作。

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)
4

2 回答 2

21

当您运行时,app.run(debug=True)您明确告诉 Flask 在基于 Werkzeug 的开发 Web 服务器上运行您的应用程序。您是否已加载 eventlet 并不重要。

如果你想在 eventlet 网络服务器上运行你的应用程序,你必须启动一个 eventlet 网络服务器,根据文档,它的启动方式如下:

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

这或多或少是socketio.run()在我的 Flask-SocketIO 扩展中所做的,选择性地处理 SSL 稍微复杂一些。执行此操作的代码行是:https ://github.com/miguelgrinberg/Flask-SocketIO/blob/539cd158f49ce085151911cb63edbacd0fa37173/flask_socketio/init .py# L391 -L408。如果您查看这些行,您会看到有三种不同的启动代码块,一种用于 werkzeug,一种用于 eventlet,另一种用于 gevent。他们都是不同的。

于 2016-01-12T15:33:40.950 回答
2
import eventlet
eventlet.monkey_patch()

不会神奇地将您的代码变成可以异步处理请求的多线程野兽(它仍然非常神奇和令人敬畏)。

正如您在此示例中看到的,您需要使用eventlet wsgi 的实现wsgi来启动服务器。

如果你想要一个标准的解决方案,看看如何使用 nginx 和 uwsgi 来启动烧瓶应用程序。您也可能对利用创建完整多线程 wsgi 处理程序的痛苦的 Spawning项目感兴趣。

于 2016-01-11T13:25:06.500 回答