我的上下文

gevent.hub.LoopExit: This operation would block forever  ,   使用过gevent queue的朋友估摸会遇到这类问题把?   我几年前就遇到过,当时因为各种原因,可以理解为懒惰,没有深究gevent的报错.     前两天写个小东西的时候,又再次遇到了block forever 问题..   这次可不能逃避了哦.

报错信息

这报错是什么意思?  gevent的hub调度器要一直循环堵塞着, 直到任务协程确保退出…  然而,你没有合理的join堵塞协程,导致调度器自个异常退出. 


该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新.

http://xiaorui.cc/?p=3717


我的业务有些繁杂,不太好作为例子讲述给大家,所以精简了一段gevent queue测试脚本.


这样执行的代码肯定会报错的….  error信息如下.

通过代码调试我们可以确定在运行gevent queue相关操作出现了问题.    我们进一步瞅瞅gevent queue的源码实现.

Queue定义了数据事件队列,getters和putters,他们使用了扩展数据类型的双端队列,  另外在构造函数里构建了hub调度器和锁标志. 

get()方法默认是block的,python queue标注库的get方法也是默认堵塞的,也就是说我单个线程一直堵塞到有任务返回.   我们清楚经过gevent所patch库不存在堵塞这么一说,这也是gevent的魅力所在.  

官方的github里有讲述虽然gevent queue默认给你个堵塞的参数,但gevent hub调取不会让你某个协程独占线程的cpu执行资源,肯定会把该任务switch切换到hub里。  我们通过_get类型方法调用__get_or_peek方法,如果qsize()为真,那么就返回结果.   你的block参数决定你是否可以立马返回.   你到了waiter =  Waiter()这一步,说明队列是空的,然后你的block为True。 这时候get_or_peek给你加几个Waiter等待事件并且扔到self.getters事件池里.    如果你timeout值,他会向hub主循环调度里面注册个超时时间, 回调函数为   Empty = __queue__.Empty .

这个跟咱们的报错是息息相关的,因为我的任务队列已经被那几个协程给消费完了,那几个协程都在做waiter操作, 这样会造成gevent的join失败, 因为你的任务流已经不存在了,都挂在queue队列的一组waiter列表里面。 你在回头看看那些报错信息,可以品味到waiter惹的祸…  此外你的那几个任务可以使用切换到自身的抽象逻辑,最简单就是加个gevent.sleep()…    这地方有些不好理解,大家可以看下gevent的调度原理.

解决的方法

解决方法有这么几个,不让他使用waiter事件,或者有一个任务一直再跑着.  

我直接采用非阻塞的方法来取结果,不管有没有都会立刻给我一个答复.   可以选择性使用gevent.sleep()减少间隔. 

需要有一个协程任务一直在跑着,这样gevent hub就可以join住整组任务流.  当然我相信你不会选择用这个方法. 

除此之外,gevent为这类生产者消费者的工作类型,扩展了一个可join的队列。 

原理也简单,JoinableQueue继承父类Queue,构造一个“未完成”的计数器,每次put任务的时候需要加一个计数, 每次触发task_done的时候才会减一。 当unfinished_tasks 为 0时,重置 self._cond.set() .

当我们执行JoinableQueue join方法时会堵塞到gevent event事件被重置才会返回…   所有,该函数运行的位置还是很重要的. 

我在stackoverflow看到有些老外对这个”gevent join block forever” 很是反感,有人把这他为gevent的一个调度bug。   其实我也是这么想的。 jamadden给予的答复是,请合理使用queue….    

这次又读了gevent hub的主调度代码,有些心得。。。 下次分享出来.


END.



对Python及运维开发感兴趣的朋友可以加QQ群 : 478476595 !!!
{ 2000人qq大群内有各厂大牛,常组织线上分享及沙龙,对高性能及分布式场景感兴趣同学欢迎加入该QQ群 }

另外如果大家觉得文章对你有些作用!   帮忙点击广告. 一来能刺激我写博客的欲望,二来好维护云主机的费用.
如果想赏钱,可以用微信扫描下面的二维码. 另外再次标注博客原地址  xiaorui.cc  ……   感谢!

源码分析之gevent monkey.patch_all实现原理

我发现最近总是跟一些python的标准库及第三方的库干上了。 平时没怎么关注,但只要一遇到问题,就想刨根问底分析源代码 ! 这样不仅解决当前问题,还能学习下...

阅读全文

python下multiprocessing和gevent的组合使用

对于有些人来说Gevent和multiprocessing组合在一起使用算是个又高大上又奇葩的工作模式.   Python的多线程受制于GIL全局锁的特性,Gevent身为协...

阅读全文

使用gevent wsgi实现长轮询Long Polling和comet

就不罗嗦了,对于实时数据的输出也这么几种,客户端自己ajax,Long Polling长轮询,comet,websocket… 当然websocket是我比较常用的,也算擅...

阅读全文