uwsgi引入gevent模块报错

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u013896457/article/details/77983393

将uwsgi日志加入:

gevent=100  #gevent协程支持,最大100个
gevent-monkey-patch=true #gevent协程补丁
发现django出现以下错误:

django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread can only be used in that same thread. The object with alias 'default' was created in thread id 140015099586432 and this is thread id 140014757277360.

解决:

去掉以下配置即可:

#gevent-monkey-patch=true #gevent协程补丁

原因待查,先记录。


另外附上:用gevent提高IO密集型的uwsgi并发(实测:当不加gevent时,uwsgi并发上去后,新的请求会被阻塞等待,只要uwsgi worker未处理完旧的请求,新请求会一直被阻塞,直到旧请求处理完毕才处理新的请求,接口sleep(5),并发100,worker24个,新请求处理完毕需要20s,这里多出来的15s都是被阻塞的时间。当加入gevent后,没有了阻塞,只要不达到uwsgi连接数上限,所有的新请求都不会被阻塞,事件循环会一直接收请求,然后给到worker去执行,所有的请求都会是5s返回。)

add by zhj:

Benchmark of Python WSGI Servers一文中,作者进行详细分析,得出的结论是gevent在所有WSGI Server(包括Tornado、Uwsgi等)中性能最好。

另外,我想说gevent适合socket IO,其它类型的IO,如磁盘IO是否适合就不清楚了。

 

原文:https://co-ding.com/?p=356#comment-6036

我的一个线上web服务在生产中遇到一个性能问题:当初为了方便选择了wsgi(众所周知wsgi协议,不像tornado之类的的框架可以使用异步IO),

而服务本身有大量IO(倒并不是带宽很大,只是会经常阻塞),因此一个业务完成可能需要很长时间几秒甚至十几秒。

我使用uwsgi这样启动:

uwsgi --harakiri 25 --harakiri-verbose --http :9090 -M  --processes 12 --threads 2 --wsgi-file wsgi.py

也就是说同时并发量为 12*2=24,这是在以后服务量增长之后是完全不能接受的。

因此,我开始考虑增加线程数,使用siege测试发现线程数过多的时候,由于线程上下文切换导致效率很低,本来5秒钟的业务,最后平均7s才能完成( 这就是线程和协程的区别,线程切换从系统层面远不止 保存和恢复 CPU上下文这么简单。操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。),

这其中有2秒钟用在了线程切换上面

siege -r 2 -c 50  "http://127.0.0.1:9090/api POST <./test.post"

于是考虑使用异步框架,tornado,gevent之类的。

我首先看了下tornado,tornado是一个web框架,它同时也提供了很多异步的库,包括httpclient(Asynchronous HTTP client)。因此我的程序要想在tornado上面跑并

发挥异步的作用,必须修改大量代码,将所有的IO操作更换成tornado提供的异步函数。这本身是不可接受的,不如直接增加进程/线程来的方便。

接下来我看了下gevent,gevent是使用greenlet协程Coroutine来实现异步网络框架,而且它提供了一个异常方便了monkey模块,可以在不修改原来

的使用python标准库函数的程序的情况下,将程序转换成可以使用gevent框架的异步程序。

即:

from gevent import monkey
# patches stdlib (including socket and ssl modules) to cooperate with other greenlets
monkey.patch_all()

gevent虽然也自带一个wsgi server,但是毕竟不是专业的web服务器,我们还是要使用uwsgi的。然后我发现uwsgi对gevent的支持还是很好的,

直接使用下面的命令启动,甚至不需要改动一行代码。(add by zhj: 在uwsgi中如果使用了gevent参数,就不能用thread参数了,不过,貌似仍可以在进程中创建线程)

uwsgi --gevent 100 --gevent-monkey-patch --http :9090 -M  --processes 4 --wsgi-file wsgi.py

--gevent参数后面的100, 制定了最大spawn 100个协程,这样我们的理论并发数可以达到 100*4。

使用了参数 --gevent-monkey-patch 让我们连最后需要修改代码的地方都没有了:它将自动调用monkey.patch_all()打补丁。

这样,我们就一句代码都没有修改,就使程序转换为异步的程序,大大提高并发数。与提高线程数相比,大大减少了线程切换的开销(协程之间切换的代价很低)。


展开阅读全文

没有更多推荐了,返回首页