为什么使用Apache + mod_wsgi运行Flask应用程序时,gevent会引发NotImplementedError?

4

我在Webfaction这个共享服务器上使用Apache(mod_wsgi)和gevent部署我的Flask应用程序时出现了问题。

在Flask提供的开发服务器中,应用程序可以正常工作。但是当我尝试进行部署时,日志文件中出现了以下错误:

[Tue Mar 13 15:48:24 2012] [error] Traceback (most recent call last):
[Tue Mar 13 15:48:24 2012] [error]   File "evdns.pxi", line 78, in gevent.core.__evdns_callback (gevent/core.c:6300)
[Tue Mar 13 15:48:24 2012] [error]   File "/home/username/.virtualenvs/staging/lib/python2.7/site-packages/gevent/hub.py", line 297, in switch_args
[Tue Mar 13 15:48:24 2012] [error]   File "/home/username/.virtualenvs/staging/lib/python2.7/site-packages/gevent/hub.py", line 290, in switch
[Tue Mar 13 15:48:24 2012] [error]   File "/home/username/.virtualenvs/staging/lib/python2.7/site-packages/gevent/hub.py", line 135, in get_hub
[Tue Mar 13 15:48:24 2012] [error] NotImplementedError: gevent is only usable from a single thread

我需要使用gevent,因为我正在使用python-requests的异步模块进行并发HTTP请求。我尝试过在谷歌上搜索,但唯一的建议是调用

from gevent import monkey
monkey.patch_all()

我已经在我的代码中做了一些事情。

WSGIDaemonProcess的值为:

WSGIDaemonProcess myapp processes=5 python-path=/home/myusername/webapps/myapp/lib/python2.7 threads=1

这是我的httpd.conf文件:http://pastebin.com/eWygicJH。有没有人能提出解决此问题的建议?请注意,不要删除任何HTML标签。

你的httpd.conf文件中WSGIDaemonProcess的值是多少? - Masci
1
可能是因为在我的经验中,如果gevent只能在其他人已经导入并以某种方式使用Python线程模块后才能进行猴子补丁,它会有些不高兴。这给我带来了很多问题。虽然还没有机会深入研究这个问题。 - Graham Dumpleton
@Masci 我更新了问题,并附上了我的httpd.conf链接和WSGIDaemonProcess的值。 - raben
我注意到你正在使用Python 2.7。我不确定monkeypatch技巧是否适用于这个版本,你能否尝试一下2.6版本? - Masci
@Masci 我会尝试切换到Python 2.6,但我不明白为什么这个问题可能与版本有关。 - raben
@Raben 抱歉,我知道 Python 2.7 存在一些问题,但它们早已被修复了。所以,除非你使用的是非常老的 gevent 版本,否则请忽略我上面的建议。 - Masci
3个回答

2
似乎我自己找到了解决方案。以下指令解决了我的问题:
WSGIApplicationGroup %{GLOBAL}

这个想法来自另一个答案,建议将WSGIApplicationGroup设置为GLOBAL以解决一个WSGI进程不断崩溃的问题。来自WSGI文档

要强制在Python初始化时创建的第一个Python子解释器中运行特定的WSGI应用程序,应使用WSGIApplicationGroup指令并将组设置为“%{GLOBAL}”。

我无法完全理解为什么这个指令可以解决我的问题,但它确实可以。如果有人能用简单明了的语言向我解释一下,我会非常高兴的;-)

请查看为什么在使用gevent的方法中,在mod_wsgi部署的Flask API中引发错误…很抱歉回复晚了,但我终于有了答案。 - horcle_buzz
为什么会是-1呢?对于“无法完全理解为什么此指示解决了我的问题,但它确实解决了”的相关回答是,“我在这里找到了答案:为什么WSGIApplicationGroup %{GLOBAL}指令适用于创建新线程”简而言之:WSGIApplicationGroup: 将执行设置为在同一个 Python 解释器下运行(第一个被创建的)。 因此,默认情况下,每个新线程都必须不使用相同的 python 解释器实例。对于 uWSGI,等效方法是将以下内容添加到您的.ini文件中:single-interpreter = true - horcle_buzz

1

尝试将monkey.patch_all()替换为monkey.patch_all(thread=False)。如果是在打补丁时导致问题的线程模块,这应该可以解决它。 request不使用线程。


谢谢Simon,我尝试了这个解决方案,但是我一直收到相同的错误。 - raben

0

我在 https://serverfault.com/a/869625/355861 下面发布了答案

apache mod_wsgi 目前不兼容 gevent。对于使用 Apache 的 AWS 弹性 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。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接