2013-07-30 132 views
0

我想完成一個我已經完成的任務,除了這次使用多線程。我必須從文件中讀取大量數據(逐行),從每行中獲取一些信息,然後將其添加到Map中。該文件超過一百萬行,所以我認爲它可能會受益於多線程。如何使用多線程來有效地使用多線程

我不確定我的方法,因爲我從來沒有在Java中使用過多線程。 我想讓主要方法進行讀取,然後將已讀取的行賦予另一個將格式化String的線程,然後將其傳遞給另一個線程以放入地圖。

public static void main(String[] args) 
{ 
    //Some information read from file 
    BufferedReader br = null; 
    String line = ''; 
    try { 
     br = new BufferedReader(new FileReader("somefile.txt")); 
     while((line = br.readLine()) != null) { 
      // Pass line to another task 
     } 


    // Here I want to get a total from B, but I'm not sure how to go about doing that 

} 


public class Parser extends Thread 
{ 
    private Mapper m1; 

    // Some reference to B 
    public Parse (Mapper m) { 
     m1 = m; 
    } 

    public parse (String s, int i) { 
     // Do some work on S 
     key = DoSomethingWithString(s); 
     m1.add(key, i); 
    } 

} 

public class Mapper extends Thread 
{ 
    private SortedMap<String, Integer> sm; 
    private String key; 
    private int value; 
    boolean hasNewItem; 

    public Mapper() { 
     sm = new TreeMap<String, Integer>; 
     hasNewItem = false; 
    } 

    public void add(String s, int i) { 
     hasNewItem = true; 
     key = s; 
     value = i; 
    } 

    public void run() { 
     while (!Thread.currentThread().isInterrupted()) { 
      try { 
       if (hasNewItem) { 
        // Find if street name exists in map 
        sm.put(key, value); 
        newEntry = false; 
       } 
      } catch (InterruptedException e) { 
       Thread.currentThread().interrupt(); 
      } 
     } 
     // I'm not sure how to give the Map back to main. 
    } 
} 

我不知道我是否採取了正確的做法。我也不知道如何終止Mapper線程並在main中檢索地圖。我將有多個Mapper線程,但我只在上面的代碼中實例化了一個線程。我只是意識到我的Parse類不是線程,但只有另一個類,如果它不覆蓋run()方法,所以我認爲Parse類應該是某種隊列。

和想法?謝謝。編輯: 感謝所有的答覆。看起來,由於I/O將成爲主要瓶頸,因此並行化將會帶來很少的效率收益。但是,出於示範的目的,我是否正確地走上正軌?不知道如何使用多線程,我仍然有點困擾。

+7

從文件中讀取是代碼的瓶頸。多線程無助於此。 –

+1

使用多線程可以在這裏拍攝你的腳。您的線程運行速度可能比@HovercraftFullOfEels指出的Disk IO速度快得多。你打算如何管理哪個線程讀取多少行。如果一個或多個線程由於某些不可預知的原因而失敗,那麼該如何處理? 我建議你在一個線程中處理一個文件,並根據手頭的機器選擇一種處理方法。如果您的服務器具有128個RAM,請將其讀入內存,然後執行處理,如果不是逐行處理。 – JVXR

回答

2

通常,I/O將比內存中任務花費更多的時間。我們將這樣的工作稱爲I/O綁定。並行性最多可能有一個微小的改進,實際上可能會讓事情變得更糟。

你當然不需要一個不同的線程來把東西放到地圖中。除非您的解析過程非常昂貴,否則您不需要其他線程。

如果你有這些任務的其他線程,他們可能會花大部分時間坐在等待下一行被讀取。

即使並行化I/O也不一定有幫助,並且可能會受到影響。即使您的CPU支持並行線程,您的硬盤驅動器可能也不支持並行讀取。

編輯:

我們所有的評論誰在這個假設的任務可能是I/O限制 - 因爲這是真正的頻繁。但是,從下面的評論來看,這種情況是一個例外。更好的答案應該包括下面的第四條評論:

測量讀取文件中所有行而不處理它們所需的時間。比較讀取和處理它們的時間。這會給你一個鬆散的上限,你可以節省多少時間。這可能會降低線程同步的新成本。

+0

所以最好的做法就是全部連續完成。 – dman33

+0

如果您將閱讀和處理分離爲兩個線程得到了一些改進,它可能很小,但需要花費更多的開發時間/風險和更復雜的代碼來維護。也就是說,我不確定我們對硬盤驅動器的評論如何適用於固態驅動器(SSD)。任何其他人都在關注與SSD並行讀取的評論? –

+0

對於演示程序,我可以使用上述方法進行任何改進?我知道這不會有太大的幫助,特別是對於生產代碼來說這可能不值得,但我仍然很好奇。 – dman33

6

爲什麼你需要多個線程?你只有一個磁盤,它只能運行得如此之快。幾乎可以肯定的是,多線程並不能幫助解決這種情況。如果確實如此,那麼從用戶的角度來看它會非常小。多線程不是你的問題。從巨大的文件中讀取是你的瓶頸。

+0

這是真的,我最大的瓶頸肯定是從文件中讀取。如果有一個線程不斷從IO中讀取,而另一個線程解析並將這些項目放入地圖,會不會有助於提高速度? – dman33

+0

@ dman33:不,它不會幫助。 –

+0

對於演示程序,我可以使用上述方法進行任何改進?我知道這不會有太大的幫助,特別是對於生產代碼來說這可能不值得,但我仍然很好奇。 – dman33

0

您不妨閱讀Amdahl's Law。由於你的大部分工作都是嚴格串行的(IO),你可以通過對其餘部分進行多線程獲得微不足道的改進。當然不值得創建水密多線程代碼的代價。

也許你應該尋找一個新的玩具例子來平行。

+0

我在使用這個例子的特定需求。目前整個程序運行時間約爲9000毫秒,單獨一行讀取輸入是800毫秒,所以我認爲如果我平行一點,至少可以看到一些改進。我在考慮只使用兩個線程,一個是閱讀,另一個是其他。 – dman33

+0

你有沒有嘗試分析你的代碼?在嘗試優化之前計算花費的時間是明智的。 –