2009-11-04 40 views
3

我有一個Python(嗯,它現在是PHP,但我們正在重寫)函數,它需要一些參數(A和B)並計算一些結果(在圖中找到從A到B的最佳路徑,圖是隻讀的) ,在典型情況下,一次呼叫需要0.1s到0.9s來完成。用戶可以將此功能作爲簡單的REST Web服務訪問(GET bestpath.php?from = A & = B)。當前的實現非常愚蠢 - 這是一個簡單的php腳本+ apache + mod_php + APC,每個請求都需要加載所有數據(在php數組中超過12MB),創建所有結構,計算路徑並退出。我想改變它。每個worker都是一個運行在循環中的python應用程序(獲取請求 - >處理 - >發送應答 - >獲取請求...)每個工人一次可以處理一個請求。我需要一些可以充當前端的東西:獲取用戶請求,管理請求隊列(可配置超時),併爲我的工作人員提供一次請求。如何處理Python工作人員長時間運行的請求?

如何處理這個?你能提出一些設置嗎? nginx + fcgi或wsgi或其他東西? HAProxy的?正如你可以看到我是一個Python新手,反向代理等我只需要一個關於架構(和數據流)的起點

btw。工作人員正在使用只讀數據,因此不需要保持它們之間的鎖定和通信

回答

1

在Python中使用線程處理這種排列的典型方法是使用標準庫模塊Queue。使用隊列模塊來管理工人的一個例子可以在這裏找到:Queue Example

2

看起來像你需要「工人」是不同的過程(至少其中一些,因此也可以讓他們所有獨立的過程,而不是比成串的線程分成幾個進程)。 Python 2.6和更高版本的標準庫中的multiprocessing模塊提供了良好的功能,可以生成一組進程並通過FIFO「隊列」與它們進行通信;如果由於某種原因,你被Python 2.5或甚至更早版本所困住,那麼PyPi存儲庫上的多處理版本可以下載並與那些較舊版本的Python一起使用。

「前端」可以也應該很容易與WSGI一起運行(使用Apache或Nginx),它可以通過multiprocessing處理與工作進程之間的所有通信,而無需使用HTTP代理等等,爲系統的那部分;只有前端本身就是一個Web應用程序,工作人員只需接收,處理和響應前端請求的工作單元。這對我來說似乎是最健康,最簡單的建築。

Python的第三方包中還有其他的分佈式處理方法,但多處理是相當體面的,並有作爲標準庫的一部分的優勢,所以,如果沒有其他特殊的限制或約束,多處理就是我想要的建議你去。

+0

多處理看起來不錯,但坦率地說,我不需要所有的功能(通信,同步等),我的工作人員是獨立的,在這種設置下,我需要在每臺服務器上安裝一個前端,對吧?我正在考慮在worker中實現基本的http解析(或者別的什麼,我不知道其他協議可以在worker和revproxy之間使用),並讓一些反向代理請求處理服務器池(工作人員在),但我不知道這種方法是否有意義,以及從哪裏開始(哪個revproxy,如何實現工作人員<-> revproxy通信等) – winter 2009-11-04 16:26:08

+0

除通信目的外您不需要同步,但您需要通信(從前端到工作的任務,從工作人員到前端的結果 - 不,你絕對不需要每個服務器的前端,你爲什麼這麼認爲?),而多處理提供的隊列對於,讓你擺脫對協議,代理和其他任何問題的擔憂 - 我認爲你急於走向的方向可能會讓你陷入一團糟的工作當中,而多處理更容易使用! – 2009-11-05 01:15:20

+0

好的,但與多處理我需要編寫2個應用程序:app1 - 一個前端進程管理隊列,app2 - 許多工作進程,對吧?那麼:app1可以在不同的machnies上管理app2嗎?是app1持久性?我的意思是 - 它的代碼和數據保持在來自web服務器的請求之間?如果沒有隊列丟失,如果是 - 它必須是異步的才能處理同時發出的請求。所以app1基本上是模仿異步網絡服務器 - 它唯一的目的是管理請求的隊列。我想避免複製已經存在的功能,這使得複雜化一切 – winter 2009-11-05 22:47:19

0

我想你可以配置modwsgi /阿帕奇所以它有幾個「熱」的Python解釋器在準備去在任何時候,還重用它們對新接入 單獨的進程 (並生成一個新的,如果他們都忙)。 在這種情況下,您可以將所有預處理的數據加載爲模塊全局變量,並且它們只會在每個進程中加載​​一次,並且每個新訪問都會重新使用它們。事實上,我不確定這不是modwsgi/Apache的默認配置 。

這裏的主要問題是,你可能最終會消耗大量的「核心」內存(但這可能不是問題) 。 我認爲你也可以配置modwsgi單進程/多 線程 - 但在這種情況下,你可能只能使用一個CPU,因爲Python全局解釋器鎖(臭名昭着的GIL)的 ,我想。

不要害怕在modwsgi郵件列表中詢問 - 它們非常友好,響應性很好。

+0

如果使用嵌入模式,只會在Apache/mod_wsgi中產生新進程,並且發生這種情況是Apache的一項功能,而不是mod_wsgi的功能。來自'http://code.google.com/p/modwsgi/wiki/ProcessesAndThreading'中描述的內存。 – 2009-11-04 22:54:28

+0

哦,還應該提到,使用嵌入模式來獲得該功能在涉及大量數據/內存時確實存在問題。見'http://blog.dscpl.com.au/2009/03/load-spikes-and-excessive-memory-usage.html'。 – 2009-11-04 22:55:37

0

您可以使用nginx負載均衡器代理PythonPaste paster(它提供WSGI,例如Pylons),它將每個請求作爲單獨的線程啓動。

1

有很多FastCGI模塊都帶有preforked模式和WSGI接口,用於python,最爲人熟知的是flup。我個人對這種任務的偏好是帶有nginx的superfcgi。兩者都將啓動多個進程並將向它們發送請求。 12Mb並不是在每個進程中分別加載它們,但是如果您想在工作者之間共享數據,則需要線程,而不是進程。請注意,在單進程和多線程的python中,由於GIL,不會有效地使用多個CPU /內核。可能最好的方法是使用多個進程(與內核一樣多),每個進程運行多個線程(superfcgi中的默認模式)。

+0

感謝您的鏈接,我不知道superfcgi。我知道GIL和我的員工是'數學'密集型的,所以我希望他們每個人都有自己的過程。我不需要工人之間的溝通。爲什麼你認爲設置進程_和_線程是最好的方法?我的意思是,當你想盡可能快地進行計算時,線程的意義何在? – winter 2009-11-05 21:49:50

+0

另外,哪一層(nginx?superfcgi?my app?)負責在這個設置中排隊(worker = process,沒有線程)?例如:我有4名工人,每人可以一次處理一個請求,現在我有10個來自用戶的請求,其中4個直接進入工作人員,但剩下的6個呢?他們應該停留在FIFO隊列中X秒。 – winter 2009-11-05 21:55:49

+0

偵聽套接字就像一個隊列。 'backlog'參數對應於等待接受的最大請求數。 'superfcgi'中的每個工人(進程或線程)只有在準備好處理請求時才接受。所以OS會爲你排隊。 – 2009-11-06 05:25:47

1

在這種情況下最簡單的解決方案是使用網絡服務器來完成所有繁重工作。當網絡服務器爲你做所有事情時,爲什麼你應該處理線程和/或進程?

在Python的部署標準的安排是:

  1. 的Web服務器上啓動多個進程每運行一次完整的Python解釋器和所有數據加載到內存中。
  2. HTTP請求進來,被分派關閉一些程序
  3. 過程並您計算並直接將結果返回給Web服務器和用戶
  4. 當你需要改變你的代碼或圖形數據,重新啓動Web服務器並返回步驟1.

這是架構使用Django和其他流行的web框架。

+0

好的,但我希望我的應用程序代碼和數據保持請求之間,我不希望解釋器reaload在每個請求。它是如何工作的? – winter 2009-11-05 22:02:32

+0

當沒有空閒進程(worker)處理請求時會發生什麼?是否有一些fifo隊列王(超時)? (抱歉,我的新手問題來自PHP世界;) – winter 2009-11-05 22:04:52

+0

應用程序代碼和數據存儲在內存中,只要進程處於活動狀態,即。永遠或直到你重新啓動它。這取決於Web服務器的配置,Apache將允許您爲每個進程設置最大數量的請求。 一般來說,網絡服務器將在必要時產生新的進程。這可以進行長度配置。請參閱Apache文檔中的MinSpareServers和MaxSpareServers。 – knutin 2009-11-06 08:20:38

0

另一種選擇是數據庫中的隊列表。
工作進程在循環中運行或關閉cron並輪詢隊列表以尋找新的作業。

相關問題