2012-01-26 52 views
3

我正在嘗試爲Linux構建一個下載加速器。我的程序使用了gevent,os和urllib2。我的程序收到一個URL並嘗試同時下載文件。我所有的代碼都是有效的。我唯一的問題是,urllib2.urlopen.read()阻止我同時運行.read()函數。Python,gevent,urllib2.urlopen.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 

我的程序的工作原理是通過調用獲取URL中的文件字節大小:

urllib2.urlopen(URL).info().get("Content-Length") 

和除數將文件大小,從而打破了下載過程分成幾部分。在這個例子中,我將下載分成10個部分。

每個greenlet在此fassion運行一個命令:

urllib2.urlopen(URL).read(offset) 

這裏是我的代碼的鏈接託管在pastiehttp://pastie.org/3253705

感謝您的幫助!

僅供參考:我在Ubuntu 11.10上運行。

+0

irc.freenode.net上的#gevent頻道可能會提供一些幫助。 – Anorov

回答

2

您正嘗試讀取來自不同greenlet的單個請求的響應。

如果您想下載使用幾個併發連接,然後如果服務器支持的話,你可以使用Range http header相同的文件(你得到206個狀態,而不是200與Range頭的要求)。見HTTPRangeHandler

1

read的參數是多個字節,而不是偏移量。

看來gevent會讓你異步地調用urllib,但不能讓你從多個greenlet訪問相同的資源。

此外,由於它使用wait_read,效果仍然是從文件中進行同步,順序讀取(與您想要實現的完全相反)。

我建議你可能需要比urllib2低一些,或者使用一個不同的庫。