为什么在 mod_wsgi 部署的 Flask api 中使用 gevent 的方法会引发有关切换线程的错误?

为什么在 mod_wsgi 部署的 Flask api 中使用 gevent 的方法会引发有关切换线程的错误?

我正在尝试通过 Apache/mod_wsgi 部署 Flask api。该 api 使用 Gevent 为递归方法提供并发性。但是,它引发了以下错误

[Mon Feb 08 12:05:37 2016] [error] error: cannot switch to a different thread
[Mon Feb 08 12:05:37 2016] [error] <callback at 0x1094ee350 args=()> failed with error

当使用 Pycharm 的内置 Web 服务器运行时,整个 api 使用 Gevent 运行良好,而当我不使用 gevent 提供并发时,api 使用 Apache/mod_wsgi 部署时运行良好。

我认为这应该可以在 Apache 中运行,但到目前为止我还没有找到解决方案。我一直看到有人提到猴子补丁,所以我在调用 gevent 的模块中添加了这一行

from gevent import monkey; monkey.patch_all()

但这似乎没有帮助。

我在 Flask 文档中找到了关于独立 WSGI 容器的这部分内容(http://flask.pocoo.org/docs/0.10/deploying/wsgi-standalone/):

Gevent is a coroutine-based Python networking library that uses greenlet to provide a high-level synchronous API on top of libevent event loop:

from gevent.wsgi import WSGIServer
from yourapplication import app

http_server = WSGIServer(('', 5000), app)
http_server.serve_forever()

它还说

There are popular servers written in Python that contain WSGI applications and serve HTTP. These servers stand alone when they run; you can proxy to them from your web server. Note the section on Proxy Setups if you run into issues.

我是否需要放弃使用 mod_wsgi,而使用 Gevent 内置的 WSGI 服务器,然后通过 Apache 进行代理?这将是一个巨大的麻烦,尤其是处理 CORS 问题(我们有一个访问同一台服务器上的 api 的 Web UI,从不同的端口进行代理会导致大量跨源问题 - 除非有人能说服我)。

对于下一步该尝试什么,任何见解都将不胜感激。

答案1

apache mod_wsgi 目前与 gevent 不兼容。对于带有 Apache 的 AWS elastic beanstalk,我为 Flask 使用了 async_mode="threading",效果很好。请注意,线程的性能不如 gevent。
https://flask-socketio.readthedocs.io/en/latest/#deployment

app = Flask(__name__,static_folder='static')
socketio = SocketIO(app, async_mode="threading") 

请注意,Flask 可以与 gevent 一起独立运行。

app = Flask(__name__,static_folder='static')
socketio = SocketIO(app, async_mode="gevent") 

if __name__ == '__main__':
    HOST = '127.0.0.1'
    PORT = 5055
    socketio.run(app, port=PORT, host=HOST)

但是,您确实需要在它前面有一个 HTTP 服务器,例如 Gunicorn。

答案2

我刚刚在这里发现了一个与我类似的帖子https://stackoverflow.com/questions/9692089/why-gevent-on-a-flask-app-with-apache-mod-wsgi-is-raising-notimplementederror有解决方案。

为了完成我需要的操作,我必须将指令添加WSGIApplicationGroup %{GLOBAL}到我的 Apache conf 中。我也很好奇为什么这可以解决问题。

答案3

我在这里找到了答案:为什么指令 WSGIApplicationGroup %{GLOBAL} 可以用于创建新线程

简而言之:

WSGIApplicationGroup:设置执行在同一个Python解释器(第一个创建的)下运行。

因此,默认情况下,每个新线程一定不能使用相同的 Python 解释器实例。

对于 uWSGI,等效的方法是将其添加到你的 .ini 文件中:

single-interpreter = true

相关内容