gevent、requests和未处理的异常
我有一段代码:
import gevent
import gevent.monkey; gevent.monkey.patch_all()
import requests
def func():
try:
requests.get('http://unavailable-host/')
except:
pass
def main():
jobs = [gevent.spawn(func) for i in xrange(10)]
gevent.joinall(jobs)
if __name__ == '__main__':
main()
这个脚本通常不会输出任何东西。但是有时候(大约每五次运行一次),我会收到这个消息:
Unhandled exception in thread started by
sys.excepthook is missing
lost sys.stderr
请告诉我,为什么会发生这种情况,以及正确的解决办法是什么?另外,如果我在
gevent.sleep(1)
之后添加
gevent.joinall(jobs)
,那么脚本就总是不会输出任何东西,一切都正常。
1 个回答
0
编辑:
这似乎与一个线程在主程序已经退出后,仍然试图执行某些操作(比如打印信息到标准输出或错误输出)有关。
可以参考 Python Bugs: issue1722344,
还有Martijn Pieters在一个类似问题的回答中的评论:
确实,这个错误是因为Python正在退出,而仍然有一个线程在活动中。
之前(完全错误)的回答:
你遇到的情况是monkey_patch
带来的一个不太愉快的副作用。
requests
库使用socket
作为在互联网上传输数据的基础机制。gevent.monkey.patch_all()
会把标准库中的socket
替换成gevent.socket
,后者是一个异步(非阻塞)的socket。因此,当代码深处(我猜是http.client
,它被urllib
使用,而urllib
又被requests
使用)执行sock.recv(X)
命令时,代码本来应该等待直到接收到X个字节或者socket关闭,但由于socket被替换成了gevent.socket
,它会立即返回当前缓冲区中已有的字节数,这样就导致了代码出错。
不过,在你的情况下,简单的解决办法是直接使用grequests,这是一个为使用gevent而构建的requests库(实际上,它自己也进行了monkey_patch)。