Python单进程hang住了

最近写了几个从网络上下载图片的python小程序,使用的urllib2进行下载,但程序跑着跑着就hang死了,进程还在,但top里面已经不见了。初始排查,添加了一些print和log输出,以及各种try...except进行检测,无果黯然神伤。

在谷歌上搜了下“python程序 hang”,出来的大多是subprocess.Popen导致的子进程hang住的问题,明显和我这没神码关系啊~我的程序就是一个简单的进程,逻辑就是按图片地址下载,很明显是下载urllib2的问题了。

搜到这篇文章How Python’s urllib2 Bit Me后,明白了是什么原因:需要设置socket的超时timeout!!正如这篇文章说的,直接使用urllib2来抓取是非常方便的,但里面的选项并没有设置socket的超时,因为它依赖于httplib库,而httplib又依赖于socket,而socket也没有设置超时的具体数值,这一层层的依赖下来,如果连接正常的话没有问题,而一旦连接超时,那就无穷尽了~

为了确定socket库确实没有设置超时,于是打开了Python库里的urllib2.py和`socket.py,可以看到如下:

def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):

可以看到urllib2.urlopen里面的timeout用的就是socket里面值。那在socket.py里呢?

_GLOBAL_DEFAULT_TIMEOUT = object()
 
def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT):
    """Connect to *address* and return the socket object.

    Convenience function.  Connect to *address* (a 2-tuple ``(host,
    port)``) and return the socket object.  Passing the optional
    *timeout* parameter will set the timeout on the socket instance
    before attempting to connect.  If no *timeout* is supplied, the
    global default timeout setting returned by :func:`getdefaulttimeout`
    is used.
    """

恩,就是个object(),根本就没设置。。注释里面虽然写道会从func:getdefaulttimeout得到默认的timeout值,但根本就没这个函数。。

其实解决方法很简单,在程序里头部加上下面的就好了:

    import socket
    socket.setdefaulttimeout(10) #设置10秒后连接超时

这在Python俱乐部的爬虫抓站的总结里写的很清楚。

简单记录下吧,以后写程序时要更加注意才是, I need more practice。