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將這些作爲工作隊列來完成。
對不起,冗長的回答。希望這可以幫助!
非常感謝米格爾對此的迴應。 (我會早一點感謝你,但我不在度假。)這非常明顯有幫助。 –