【问题标题】:Responding to concurrent requests with Flask and eventlet使用 Flask 和 eventlet 响应并发请求
【发布时间】:2016-04-15 19:17:48
【问题描述】:

我尝试设置一个最小的 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)

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

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

顺便说一句,当我使用the Flask-socketio library 运行网络服务器时,根据文档,如果安装了它会自动选择 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)

【问题讨论】:

    标签: python flask eventlet flask-socketio


    【解决方案1】:

    当您运行app.run(debug=True) 时,您明确告诉 Flask 在基于 Werkzeug 的开发 Web 服务器上运行您的应用程序。加载 eventlet 没关系。

    如果你想在eventlet web服务器上运行你的应用程序,你必须启动一个eventlet web服务器,根据the documentation启动如下:

    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。它们都是不同的。

    【讨论】:

    • 太棒了!在 eventlet 文档中的示例中,我并不清楚必须将 Flask 应用程序对象传递给 wsgi.server 命令,因此这个基于 Flask 的示例非常有帮助。
    【解决方案2】:
    import eventlet
    eventlet.monkey_patch()
    

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

    正如您在this example 中看到的,您需要使用eventlet wsgi's implementation 启动wsgi 服务器。

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

    【讨论】:

    • 好吧,我明白了,切换到野兽模式并不容易。但是,flask-socketio 是如何处理这个问题的呢?至少,在“部署/嵌入式服务器”in the docs 下,它显示为Note that socketio.run(app) runs a production ready server when eventlet or gevent are installed.,无需进一步详细说明。既然选择了 uWsgi/NGINX is some work to do,那么像上面那样使用 flask-socketio 有什么缺点吗?
    猜你喜欢
    • 2018-07-14
    • 1970-01-01
    • 2016-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-24
    • 2017-01-31
    • 1970-01-01
    相关资源
    最近更新 更多