2015-06-10 82 views
3

我手頭上的任務是讀取大文件的行,處理它們,並返回有序的結果。erlang進程和消息傳遞體系結構

我的算法是:

  1. 開始與主過程,將評估的工作負荷(寫在該文件的第一行)
  2. 產卵工作進程:每個工人將讀取的文件的一部分使用前綴/ 3,處理該部分,並將結果發送給主設備
  3. 主設備接收所有子結果,進行排序並返回 因此基本上不需要工作人員之間的通信。

我的問題:

  1. 如何找到Erlang進程的數目和內核的數量之間的最佳平衡?所以如果我爲每個處理器內核產生一個進程,我將使用我的cpu?
  2. pread/3如何到達指定的行;它遍歷文件中的所有行嗎?並且pread/3是一個很好的並行文件讀取計劃?
  3. 從流程A發送一條大消息到B還是發送N條小消息會更好嗎?我發現在下面的鏈接部分答案,但我希望進一步闡述
    erlang message passing architecture
+1

文件內存映射了嗎?如果沒有,那麼讓多個演員隨機訪問該文件的不同部分可能會[減慢你的速度](http://stackoverflow.com/questions/17220892/read-the-30million-user-ids-one-by-one-from -the-big-file/17220973#17220973),因爲只有一個演員可以在任何時候讀取磁盤,如果你有磁盤,那麼每個演員都會觸發磁盤尋道。我建議讓主映射文件的全部(或大部分,如果文件很大)映射到內存中,然後讓工作人員在這個內存映射(部分)文件上操作。 –

+2

@ Zim-ZamO'Pootertoot是對的。通常,我的方法是讓「主」逐行讀取文件(或逐段讀取),然後將這些行分配給多個「工作人員」進行處理。如果您以二進制(而非列表)字符串讀取文件,這可能非常快,因爲大於64字節的二進制文件被引用計數,並且在將消息發送到另一個進程時具有較低的複製開銷。 –

+1

原則上我同意。然而,由於erlang和[line_sever模塊](https://github.com/dcaoyuan/snippet/blob/master/widefinder/src/line_server_modified.erl)中的緩慢seo的io,2007年一直很流行。它同時讀取文件。我現在想了8年後,最好的辦法是什麼。 – ErlangNewbie

回答

1
  1. Erlang進程很便宜。你是免費的(鼓勵)使用比你擁有的核心更多的內核。對於您的問題實際可能有一個上限(每行一個進程中加載​​1TB的數據要求一點點,取決於行的大小)。

    當你不知道的時候,最簡單的方法就是讓用戶決定。這意味着你可以決定產生N工人,並在他們之間分配工作,等待回聽。如果您不喜歡它的運行方式,請在更改N時重新運行該程序。

    更簡單的做法是對一堆時間進行基準測試,挑選您認爲最有價值的東西,將其放在池庫中(如果您想要;某些池用於預先分配的資源,可調整的金額),並且決定採取什麼樣的萬能解決方案。

    但的確,沒有簡單的'最佳核心數量'。如果你願意,你可以在50個進程和65,000個進程上運行;如果這項任務是尷尬並行的,那麼虛擬機應該能夠使用它們中的大部分,並使核心飽和。

-

  • 並行文件讀取是一個有趣的問題。它可能會也可能不會更快(正如直接評論所提到的),如果每行的工作量足夠小,以至於讀取文件的成本最高,它可能只會加快速度。

    棘手的一點是,像pread/2-3這樣的函數需要一個字節偏移量。你的問題是這樣的,你擔心文件的。你交給工人的字節偏移可能因此最終跨越一條線。如果您的塊最後以my的單詞this is my line\nhere it goes\n結尾,則一位工作人員會看到自己的行數不完整,而另一位工作人員只會報告my line\n,缺少之前的this is

    一般來說,這種煩人的東西是什麼會導致你有第一個進程擁有該文件並通過它篩選,只是交出文本處理給工人;那麼這個過程將成爲某種協調員。

    該策略的好處在於,如果主進程知道作爲消息發送的所有內容,它也知道何時接收到所有響應,從而很容易知道何時返回結果。如果一切都不相連,你必須相信發起人和工作人員告訴你「我們都失業了」,作爲一組獨立的消息來了解。

    實際上,您可能會發現最有助於知道哪些操作有助於您的硬件在文件操作方面的生活,而不僅僅是「有多少人可以一次讀取文件」。只有一個硬盤(或SSD),無論如何所有數據都要經過它;並行性在最終訪問時可能會受到限制。

  • -

  • 使用的消息,對於你的程序是有意義的。最高性能的程序將有很多進程能夠工作而無需傳遞消息,進行通信或獲取鎖定。

    一個更現實的非常高性能的程序會使用非常少量的消息。

    這裏有趣的是你的問題本質上是基於數據的。因此,您可以執行以下幾項操作:

    • 確保您以二進制格式讀取文本;大的二進制文件(> 64b)被分配到一個全局二進制堆上,共享和引用計數GC'd
    • 提交有關需要完成的內容而不是數據的信息;這個需要測量,但引導過程可能會覆蓋文件,記錄行結束的位置,並且只需要手動向工作人員發送字節偏移量,以便他們可以自行讀取文件;請注意你最終會讀取文件兩次,所以如果內存分配不是你的主要開銷,這可能會更慢
    • 確保在rawram模式下讀取文件;其他模式使用中間人過程來讀取和轉發數據(如果您通過集羣Erlang節點中的網絡讀取文件,這非常有用); rawram模式將文件描述符直接提供給調用進程,速度更快。
    • 首先擔心寫一個清晰,可讀和正確的程序。只有在它太慢時纔會嘗試重構並優化它;第一次嘗試可能會很好。
  • 我希望這有助於。

    P.S.你可以先嚐試真正簡單的東西:

    1. 之一:

      • 讀取整個文件,{ok, Bin} = file:read_file(Path)和分割線(與binary:split(Bin, <<"\n">>, [global]))一次,
      • 使用{ok, Io} = file:open(File, [read,ram])然後用file:read_line(Io)關於文件描述符重複
      • 使用{ok, Io} = file:open(File, [read,raw,{read_ahead,BlockSize}])然後重複使用file:read_line(Io)上的文件描述符
    2. 呼叫rpc:pmap({?MODULE, Function}, ExtraArgs, Lines)自動運行並行一切(它將產生每行一個處理)的結果

    3. 呼叫lists:sort/1

    然後從那裏你可以改進每一步,如果你確定他們是有問題的。

    +0

    非常感謝。經過幾次測試後,我一次性讀取文件作爲二進制文件,並使用binary:part/2分割工作,因爲這些行的大小是固定的。我還分配了一組進程,它的縮放比例非常好,但它仍然有點慢,我會嘗試使用筆記進行優化,完成後我將在此處發佈代碼和加速圖 – ErlangNewbie