2015-06-17 90 views
6

我一直在使用燒瓶,並且我的一些路由處理程序開始可能需要幾分鐘才能完成的計算。使用flask的開發服務器,我可以使用app.run(threaded = True),並且當它關閉執行這些多分鐘計算時,我的服務器將繼續響應其他請求。threading = True with flask-socketio

現在我已經開始使用Flask-SocketIO,我不知道如何做同樣的事情。我知道,我可以在python的任何時候顯式地產生一個單獨的線程,從任何時候開始這些計算之一。這是做到這一點的唯一方法嗎?或者是否存在與flask-socketio的threaded = True相同的內容。 (或者更可能是我完全困惑。)

感謝您的任何幫助。

回答

13

Flask/Werkzeug中線程化模式的思想是使開發服務器能夠同時處理多個請求。在默認模式下,服務器可以一次處理一個請求,如果客戶端在服務器正在處理先前請求的同時發送請求,則第二個請求必須等到第一個請求完成。在線程模式下,Werkzeug爲每個傳入請求生成一個線程,因此可以同時處理多個請求。您顯然正在利用線程模式來請求返回很長的請求,同時保持服務器對其他請求的響應。

請注意,當您離開開發Web服務器並進入生產Web服務器時,此方法難以正確擴展。對於基於服務器的服務器,您必須選擇固定數量的工作人員,併爲您提供最大數量的併發請求。

另一種方法是使用基於協同程序的服務器,例如gevent,它完全受Flask支持。對於gevent來說,只有一個工作進程,但其中有多個輕量級(或「綠色」)線程,它們協作允許對方運行。在這種模式下工作的關鍵是確保這些綠色線程不會濫用CPU時間,因爲一次只能運行一個CPU。如果這樣做是正確的,那麼服務器可以比使用上述多工作者方法更好地擴展,並且您可以輕鬆地以這種方式處理數百/數千個客戶端。

所以現在你想使用Flask-SocketIO,並且這個擴展需要使用gevent。如果這個要求的原因不明確,與HTTP請求不同,SocketIO使用WebSocket協議,這需要長期連接。使用gevent和綠色線程可以使潛在的大量不斷連接的客戶端成爲可能,這對於多個員工來說是不可能的。

問題是你的長時間計算,這對gevent類型的服務器不友好。爲了使它工作,你需要確保你的計算函數經常產生,以便其他線程有機會運行並且不會餓死。例如,如果你的計算函數在一個循環中,你可以做這樣的事情:

def my_long_calculation(): 
    while some_condition: 
     # do some work here 

     # let other threads run 
     gevent.sleep() 

sleep()功能將基本遏制你的線程,並切換到需要CPU的任何其他線程。最終控制權將返回給您的功能,並在此時進入下一次迭代。您需要確保睡眠呼叫不會太遠(因爲這會使應用程序的其餘部分無響應)或不太接近(因爲這可能會減慢計算速度)。

因此,要回答你的問題,只要你在較長的計算正確屈服,你不需要做任何特殊處理的併發請求,因爲這是GEVENT的正常工作模式。

如果由於任何原因產量方法不可行,那麼您可能需要考慮將CPU密集型任務卸載到另一個進程。也許可以使用Celery將這些作爲工作隊列來完成。

對不起,冗長的回答。希望這可以幫助!

+0

非常感謝米格爾對此的迴應。 (我會早一點感謝你,但我不在度假。)這非常明顯有幫助。 –