2014-12-05 105 views
2

所以我有一個程序運行一堆不同的計算,然後返回一個結果,當所有的計算完成。爲什麼我的代碼在Java中使用多線程的速度較慢?

本來我的代碼是同步的類似如下:

public class MyApplication{ 

    public static void main(String[] args) { 
     doCalculation(1); 
     doCalculation(2); 
     doCalculation(3); 
     doCalculation(4); 
     doCalculation(5); 
     doCalculation(6); 
     doCalculation(7); 
     doCalculation(8); 

     /* Print result */ 
    } 
} 

我認爲這將是更有效的,現在我有一些像運行在新線程這些計算,

public class MyApplication{ 
    public static void main(String[] args) { 
     List<Thread> threads = new ArrayList<Thread>(); 
     threads.add(doCalculation(1)); 
     threads.add(doCalculation(2)); 
     threads.add(doCalculation(3)); 
     threads.add(doCalculation(4)); 
     threads.add(doCalculation(5)); 
     threads.add(doCalculation(6)); 
     threads.add(doCalculation(7)); 
     threads.add(doCalculation(8)); 

     for(Thread t : threads){ 
      if(t.isAlive()){ 
       try{ 
        t.join(); 
       } catch(InterruptedException e) { 
        System.out.println("Error calculating fitness"); 
       } 
      } 
     } 

     /* Print result */ 
    } 
} 

我對不起,我是一個完整的初學者線程。如果我不得不猜測我會假設我產生了兩個很多的新線程(在我的應用程序中有大約50個計算),但任何建議都會非常感謝!

+0

而我之前並不知道:O列表中的線程。有趣! – Anurag 2014-12-05 21:55:10

+0

doCalculation()可能不會花費足夠的時間來抵消線程創建的開銷。 – 2014-12-05 22:01:11

回答

3

爲了獲得最佳並行性,線程數不得超過可用CPU核數量,除此之外的所有內容只會產生上下文切換開銷。而且,創建線程非常昂貴,因此在完成一次計算後讓線程死亡是一大浪費。相反,您應該依賴於Java庫提供的對並行性的出色支持。

我的建議是使用Java 8流API和制定您的問題作爲平行流,如

IntStream.range(1, 9).map(this::doCalculation).parallel().collect(Collectors.toList()); 

這將在共同ForkJoinPool,默認情況下是根據大小來執行CPU核心數。

我假設你正在進行並行化的整體工作需要在單個內核上花費大量時間(至少幾毫秒),並且不涉及I/O,因爲這些是並行化非常基本的先決條件。如果沒有足夠的工作要做,任務切換到線程和結果集的開銷將消除並行處理的任何優勢。如果您執行任何I/O,則會發生阻塞,並在CPU處於空閒狀態時佔用一個線程。

5

每個線程都有開銷和加入開銷。如果線程所做的工作很重要,那麼開銷是值得的;但如果doCalculation非常快,那麼開銷就會壓倒它。

一般來說,線程不會讓事情變得更快 - 它們只是讓更多事情一下子就完成。如果每個線程有大量的工作,並且多線程可以同時以全速運行(這是多個CPU內核的幫助),這可能是值得的。

如果每個doCalculation需要X時間,並且你有8個(因此8T開銷,其中T是每個線程的開銷量),那麼如果8T > 8TX整個程序將花費更長的時間 - 也就是說,如果旋轉8個線程的開銷大於順序執行全部8個計算的工作量。

+0

在適當的方法中,線程不會爲每個單獨的計算而旋轉,因此基本開銷要小得多,並且來自任務切換和結果收集。 – 2014-12-05 22:02:37

+1

@MarkoTopolnik確實如此,但從這個例子看來,OP實際上是手動創建和啓動線程的(儘管在仔細閱讀時,他們從未真正調用過't.start()'!) – yshavit 2014-12-05 22:04:53

+0

你說的話可能適用於OP的代碼,但重要的是他的方法可以大大改善,最終目標是通過並行來加速。 – 2014-12-05 22:05:39

相關問題