我正在尝试通过 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