2011-06-07 21 views
3

假設我必須從其中有很多大型XML文件的目錄中讀取數據,我必須解析並通過網絡將它們發送給某個服務,然後再將響應寫入磁盤。您如何規範Erlang中的併發/相關進程性能?

如果是Java或C++等,我可以做這樣的事(希望這是有道理的):

(File read & xml parsing process) -> bounded-queue -> (sender process) -> service 

service -> bounded-queue -> (process to parse result and write to disk) 

然後我的線程分配給每個進程的任何適當的數目。這樣我就可以將每個進程的併發性限制在最佳值,並且有界的隊列將確保不會出現內存不足等問題。

雖然在Erlang編碼時應該怎麼做?我想我可以在一個函數中實現整個流程,然後迭代目錄並儘可能快地產生這些「開始 - 結束」進程。這聽起來並不理想,因爲如果解析XML需要比讀取文件等應用程序更長的時間。可能會因內存中的許多XML文檔等而導致內存不足,並且無法將併發性保持在最佳級別。例如。如果「服務」在併發性爲4時最有效,那麼通過巨大的併發性來實現它將是非常低效的。

erlang程序員應該如何處理這種情況?即什麼是固定線程池和有界隊列的erlang替代品?

回答

2

除了通過及時處理它們之外,沒有真正的方法來限制進程的隊列大小。最好的方法是在產卵之前簡單地檢查可用資源,如果它們不足,則等待。所以如果你擔心內存,請在產生新進程之前檢查內存。如果光盤空間,檢查磁盤空間等。

限制產生的進程數也是可能的。一個簡單的構造是:

pool(Max) -> 
    process_flag(trap_exit, true), 
    pool(0, Max); 
pool(Current, Max) -> 
    receive 
     {'EXIT', _, _} -> 
      pool(Current - 1, Max); 
     { work, F, Pid} when Current < Max -> 
      Pid ! accepted, 
      spawn_link(F), 
      pool(Current + 1, Max); 
     { work, _, Pid} -> 
      Pid ! rejected, 
      pool(Current, Max); 
    end. 

這是一個粗略的草圖,一個進程將如何限制它產生的進程的數量。然而,認爲限制真實原因而不是人造數字會更好。

3

你絕對可以在Erlang中運行你自己的進程池,但這是一種很差的內存使用方式,因爲它沒有考慮到正在讀取的XML數據的大小(或者進程使用的總內存物)。

我建議按照您的建議在功能庫中實現整個工作流程,並生成執行此工作流程的流程。添加內存使用情況檢查,查看要讀入的數據大小和可用內存(提示:使用memsup)。

+0

感謝您的回答!如果我關心的不是記憶,例如如果我想與特定併發的服務交談,那麼使用進程池是否好? *編輯*:我想我從DefLog得到了答案 – 2011-06-07 23:54:03

+0

他基本上得出了和我一樣的結論。而且基於固定數量的進程進行限制並沒有真正的意義,實際上並沒有告訴你什麼(除非這是你的確切要求:同時不超過N個併發任務)。 – 2011-06-08 08:49:50

1

我建議你在事件驅動的範例中做。

想象一下,您啓動了帶有文件名列表的OTP gen_server。

  1. gen_servers檢查資源,併產生如果允許的話,從列表中刪除文件名,並把它傳遞給下一個工人工人。

  2. 工作人員處理文件並在準備就緒時將消息強制轉回給gen_server(或者您可以僅捕獲EXIT)。

  3. gen_server接收到此類消息並執行步驟1,直到文件列表爲空。

因此,工人們做了繁重的工作,gen_server控制着流程。

您也可以創建分佈式系統,但它有點複雜,因爲您需要在每臺計算機上產生中間gen_servers,並在資源可用時查詢它們,然後根據回覆選擇哪臺計算機處理下一個文件。你可能需要像NFS這樣的東西來避免發送長消息。

如果您需要更多的併發性,工人可以進一步拆分。

+0

這是否意味着gen_server中有某種信號量並集中控制併發等。 – 2011-06-07 23:55:05

+0

我不確定內部實現,但Erlang消息傳遞確實類似於具有無限隊列容量的消費者/生產者模型(生產者永遠不會阻止),這通常是使用信號量實現的。 – 2011-06-08 02:18:20