前言:
尼玛悲剧呀,今天被一个小问题折腾死了,场景很简单,产品经理说,大量的节点的数据都不动了,哥们一听,这个火呀。 怎么可能,哥们写的代码这么健壮。
[ruifengyun@bj-buzz-dev01 ~]$ sudo strace -p 2583 Process 2583 attached - interrupt to quit futex(0x1f71e10, FUTEX_WAIT_PRIVATE, 0, NULL
调用salt api批量一看,进程还都是存在的,时间片貌似也有。因为前几天 上线了个关于Hbase的batch的逻辑和数据的本地化缓存的fix,然后就开始纠结了,来来回回检查了好几遍这两个逻辑,但是实在是没啥问题。 只能是上大杀器strace了,用strace追踪pid,看到的结果是 futex, FUTEX_WAIT_PRIVATE的现象。
嗯哼,原文地址是 blog.xiaorui.cc
原来是 FUTEX_WAIT_PRIVATE呀,这个现象哥以前碰见过,是发生在redis 堵塞的情况,那么问题来了,我这边的逻辑没有redis的。 最后确定到是python queue的问题。
解决的方法,queue 的 get() 是堵塞的。如果你是多线程去判断queue的大小,然后同时去取任务,如果这个时候,你的任务的数量小于线程的数目的时候,没有取到任务的线程就会被你的get()堵塞掉。
你可以用get(timeout=2)做超时的控制,queue模块还有个get_,或者是在判断队列大小和get队列的时候,用mutex lock堵塞锁定这个逻辑。
不管是多线程还是多进程 lock 锁只是需要在共享变量的地方改变就可以了。如果在整个逻辑里面使用锁的花,那就没有多线程的意义了。
if mutex.acquire(1): num = num+1 msg = self.name+' set num to '+str(num) print msg mutex.release()
In [1]: import Queue In [2]: q = Queue.Queue() In [3]: q.get q.get q.get_nowait In [3]: q.get_nowait() --------------------------------------------------------------------------- Empty Traceback (most recent call last) ---- 1 q.get_nowait() /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/Queue.pyc in get_nowait(self) 188 raise the Empty exception. 189 """ 190 return self.get(False) 191 192 # Override these methods to implement other queue organizations /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/Queue.pyc in get(self, block, timeout) 163 if not block: 164 if not self._qsize(): 165 raise Empty 166 elif timeout is None: 167 while not self._qsize(): Empty: In [4]: q.get()堵塞中... ...
太粗心了, 好久没用多线程了, 这段时间基本在用gevent协程,gevent是可以保证数据的安全性质的。 总之,记得以后threading要记得加锁 [ mutex ]!!!
真是经验呀
广告小点啊。。
啥广告呀? 你说的是爬虫的那个么? 总是被爬虫爬,尼玛受不鸟了。
我喜欢作者这风格
哈哈