这个点下班真实罪恶
今天一个跑了好久的一个项目突然gg,程序执行到一半抛了个mysql异常,误以为连接超时,搞了半天排除不是mysql问题。
加log后发现是子进程退出时其他进程获取不到状态,导致程序阻塞,一直等待子进程退出。关键是一模一样的代码另一台机器上完全没问题,查询python版本也完全一致
当时并未想到是第三方模块的问题。尝试了多种方式都无法通知其他进程,开始以为是子进程之间无法通信,写了测试代码,并没有问题。然后就开始撸项目代码,突然看到另一个函数子进程可以正常退出并通知,对比下一个是gevent.sleep, 一个是time.sleep,文件头引入了from gevent import monkey; monkey.patch_os(),把monkey注释掉,程序竟然正常运行了
测试发现,使用patch_os后,os.fork就会被gevent.fork,此时循环阻塞如果是time.sleep,就永远获取不到进程状态,改成gevent.sleep 程序又能正常运行,两种解决方案都可
对比了两台机器环境发现问题版本是gevent 1.1.1,正常 gevent 1.0.1,想起来之前做另一个项目时升级过包版本,果然是跳出来的猴子,
纪录下引以为戒。涉及进程协程的代码,尽量保持一致,另外python3 真香远离python2
测试代码
import os,time,gevent
from gevent import monkey; monkey.patch_os()
def fork2():
pid = os.fork()
if pid == 0:
print "11111",os.getpid()
else:
print "00000",os.getpid()
res = os.waitpid(pid, os.WNOHANG)
print "id2 res",res
if pid == 0:
time.sleep(1)
print "exit id2",os.getpid()
os._exit(0)
else:
time.sleep(5)
print "id2",pid
res = os.waitpid(pid, os.WNOHANG)
time.sleep(2)
print "id2 res",res
def fork1():
pid = os.fork()
if pid == 0:
print "id1",os.getpid()
fork2()
os._exit(0)
else:
print "id0",os.getppid()
res = os.waitpid(pid, os.WNOHANG)
print "id1 res", res
while res == (0,0) :
print 6666
res = os.waitpid(pid, os.WNOHANG)
print "id1 res", res
if res != (0,0):
break
time.sleep(1)
fork1()
print "end"



