Python, gevent, urllib2.urlopen.read() 下载加速器
我正在尝试为Linux构建一个下载加速器。我的程序使用了gevent、os和urllib2这几个库。程序会接收一个网址,然后试图同时下载文件。我的代码都是正确的。唯一的问题是,urllib2.urlopen.read()这个函数让我无法同时运行.read()。
这是我遇到的异常信息。
Traceback (most recent call last):
File "/usr/lib/pymodules/python2.7/gevent/greenlet.py", line 405, in run
result = self._run(*self.args, **self.kwargs)
File "gevent_concurrent_downloader.py", line 94, in childTasklet
_tempRead = handle.read(divisor) # Read/Download part
File "/usr/lib/python2.7/socket.py", line 380, in read
data = self._sock.recv(left)
File "/usr/lib/python2.7/httplib.py", line 561, in read
s = self.fp.read(amt)
File "/usr/lib/python2.7/socket.py", line 380, in read
data = self._sock.recv(left)
File "/usr/lib/pymodules/python2.7/gevent/socket.py", line 407, in recv
wait_read(sock.fileno(), timeout=self.timeout, event=self._read_event)
File "/usr/lib/pymodules/python2.7/gevent/socket.py", line 153, in wait_read
assert event.arg is None, 'This event is already used by another greenlet: %r' % (event.arg, )
AssertionError: This event is already used by another greenlet: (<Greenlet at 0x2304958: childTasklet(<__main__.NewFile object at 0x22c4390>, 4595517, <addinfourl at 37154616 whose fp = <socket._fileob, 459551, 1)>, timeout('timed out',))
<Greenlet at 0x2304ea8: childTasklet(<__main__.NewFile object at 0x22c4390>,4595517, <addinfourl at 37154616 whose fp = <socket._fileob, 7, -1)failed with AssertionError
我的程序通过调用以下方式获取网址的文件字节大小:
urllib2.urlopen(URL).info().get("Content-Length")
然后我把文件大小除以一个数,这样就把下载过程分成了几个部分。在这个例子中,我把下载分成了10个部分。
每个绿色线程(greenlet)都是这样运行命令的:
urllib2.urlopen(URL).read(offset)
这是我代码的链接,托管在pastie上: http://pastie.org/3253705
谢谢你的帮助!
顺便说一下:我是在Ubuntu 11.10上运行的。
2 个回答
2
传给 read
的参数是字节数,而不是偏移量。
看起来 gevent 允许你异步调用 urllib,但不允许你从多个绿色线程同时访问同一个资源。
而且,由于它使用了 wait_read,所以效果仍然是从文件中同步、顺序地读取(这和你想要的完全相反)。
我建议你可能需要使用比 urllib2 更底层的东西,或者换一个不同的库。
2
你想要从不同的绿色线程(greenlets)中读取同一个请求的响应。
如果你想用多个同时连接来下载同一个文件,可以使用Range
HTTP头,前提是服务器支持这个功能(这样你会收到206状态码,而不是200状态码,表示你使用了Range头的请求)。详细信息可以查看HTTPRangeHandler
。