2015-08-21 23 views
7

假設我有一個長期運行的功能:Python的龍捲風 - 困惑如何阻塞函數轉換成一個無阻塞功能

def long_running_function(): 
    result_future = Future() 
    result = 0 
    for i in xrange(500000): 
     result += i 
    result_future.set_result(result) 
    return result_future 

我有一個處理一個get函數與上述結果打印用戶for循環,增加了在所有的xrange數量:

@gen.coroutine 
def get(self): 
    print "start" 

    self.future = long_running_function() 
    message = yield self.future 
    self.write(str(message)) 

    print "end" 

如果我同時運行兩個網絡瀏覽器上面的代碼中,我得到:

開始

開始

這似乎是阻止。從我的理解中,@gen.coroutineyield語句不阻止IOLoop在get函數,但是,如果這是阻斷協程內的任何功能,那麼它會阻止IOLoop。

因此,我做的另一件事是將long_running_function變成一個回調,並使用yield gen.Task來代替。

@gen.coroutine 
def get(self): 
    print "start" 

    self.future = self.long_running_function 
    message = yield gen.Task(self.future, None) 
    self.write(str(message)) 

    print "end" 

def long_running_function(self, arguments, callback): 
    result = 0 
    for i in xrange(50000000): 
     result += i 
    return callback(result) 

這不切得,它給了我:

開始

開始

我可以使用線程來執行那些平行,但它似乎並沒有要走的路,因爲我可能會開了很多THRE廣告,並根據龍捲風的用戶指南,它可能是昂貴的。

人們如何寫龍捲風異步庫?

回答

6

如果阻塞函數是CPU綁定的(就像你的for/xrange例子那樣),那麼線程(或者進程)是使它無阻塞的唯一方法。創建每個傳入請求的線程是昂貴的,但做一個小的ThreadPoolExecutor來處理所有CPU綁定操作是沒有的。

爲了使功能無阻塞,而無需使用螺紋,該函數必須是事件驅動:它必須等待某些外部事件(例如,網絡I/O),以便它可以被喚醒時該事件發生。

+0

我認爲你是對的,但是[Calling-blocking-functions](htt p://www.tornadoweb.org/en/stable/guide/coroutines.html#calling-blocking-functions)沒有提到CPU綁定或事件驅動,它只是說:「最簡單的方法來調用來自協同程序的阻塞函數是使用ThreadPoolExecutor,它返回與協程兼容的Futures「 –

0

我目前正在努力增加一個網絡接口,使用龍捲風和WebSocket的功能,我的模擬程序。 我的仿真程序是計算密集型的,即由@ ben-darnell說的CPU限制任務,應該使用另一個線程進程來實現。

多次調查之後,我覺得這些資源可能會有所幫助:

我現在在做類似的實現,並且會更新這個答案時,我有更多的進展:)