2017-07-24 58 views
0

我目前正在開發python3(仍然初學者)在tornado框架和我有一個功能,我想在後臺運行。更確切地說,該功能的任務是下載一個大文件(塊大塊),並可能在每個塊下載後做更多的事情。但是調用函數不應該等待下載函數完成,而應該繼續執行。蟒蛇龍捲風並行運行功能

這裏是一些代碼示例:

@gen.coroutine 
def dosomethingfunc(self, env): 
    print("Do something") 

    self.downloadfunc(file_url, target_path) #I don't want to wait here 

    print("Do something else") 


@gen.coroutine 
def downloadfunc(self, file_url, target_path): 

    response = urllib.request.urlopen(file_url) 
    CHUNK = 16 * 1024 

    with open(target_path, 'wb') as f: 
     while True: 
      chunk = response.read(CHUNK) 
      if not chunk: 
       break 
      f.write(chunk) 
      time.sleep(0.1) #do something after a chunk is downloaded - sleep only as example 

我讀過計算器https://stackoverflow.com/a/25083098/2492068這個答案,並試圖使用它。

其實我以爲如果我用@gen.coroutine但沒有yielddosomethingfunc會繼續等待downloadfunc完成。但實際上該行爲是相同的(與產量或無) - "Do something else「將只被打後downloadfunc完成下載

我錯過這裏什麼

回答

2

以效益龍捲風的異步的,必須有yielded? 。在某些時候非阻塞功能由於downloadfunc代碼全都阻塞,直到調用的函數完成的dosomethingfunc不拿回控制

有情侶的問題與您的代碼:

所以downloadfunc可能看起來像:

@gen.coroutine 
def downloadfunc(self, file_url, target_path): 

    client = tornado.httpclient.AsyncHTTPClient() 

    # below code will start downloading and 
    # give back control to the ioloop while waiting for data 
    res = yield client.fetch(file_url) 

    with open(target_path, 'wb') as f: 
     f.write(res) 
     yield tornado.gen.sleep(0.1) 

要使用流媒體實現它(按塊)支持,你可能想這樣做:

# for large files you must increase max_body_size 
# because deault body limit in Tornado is set to 100MB 

tornado.web.AsyncHTTPClient.configure(None, max_body_size=2*1024**3) 

@gen.coroutine 
def downloadfunc(self, file_url, target_path): 

    client = tornado.httpclient.AsyncHTTPClient() 

    # the streaming_callback will be called with received portion of data 
    yield client.fetch(file_url, streaming_callback=write_chunk) 

def write_chunk(chunk): 
    # note the "a" mode, to append to the file 
    with open(target_path, 'ab') as f: 
     print('chunk %s' % len(chunk)) 
     f.write(chunk) 

現在,您可以在dosomethingfunc中調用它,而不需要yield,並且該函數的其餘部分將繼續。

編輯

修改塊大小不被支持(曝光),無論是從服務器和客戶端。您也可以看看https://groups.google.com/forum/#!topic/python-tornado/K8zerl1JB5o

+0

非常感謝您的示例 - 我並不瞭解阻止所有時間的功能,但確定它是有意義的。不幸的是,我試圖實現你的解決方案,但我得到一個「內容長度」太長的執行(我的文件大約爲1,5GB)。但它不應該是一個使用分塊下載的問題。任何想法爲什麼我得到這個消息? – spcial

+1

龍捲風的身體限制設置爲100MB,你可以用'max_body_size'覆蓋它,例如。 'AsyncHTTPClient(max_body_size = 2000000000)' – kwarunek

+0

我試過usnig'AsyncHTTPClient(max_body_size = 2000000000)',但它對我沒有任何影響 - 主體大小保持不變。如果我嘗試與SimpleAsyncHTTPClient一樣的工作,但如何定義塊大小?我可以從我的網絡監視器看到它開始下載,但在20秒後(可能是因爲標準超時),它只是暫停而不寫入塊。有沒有什麼辦法來定義塊的大小? – spcial