2012-07-06 51 views
2

如果我有2個CPU和時間表1000個任務的fork/join框架上下工夫,將任務最多2個在同一時間執行,或者將更多的任務可以並行在同一個CPU上執行? (比方說,也許一個任務正在等待I/O,在這種情況下,CPU會變成閒置,而另一個線程可以運行)是fork/join多線程?

+0

如果您有2個CPU和1個硬盤,您可能需要3個或更多任務。 1000不太可能是最佳選擇。 – 2012-07-06 21:17:18

+0

我有一個未知數量的CPU,而I/O只是一個例子。它可能是任何可以使CPU時間可用的事情,如果它是I/O,它也可以是網絡。 – rid 2012-07-06 21:26:47

回答

0

我做了一個測試,以驗證這一點:

import java.util.concurrent.*; 

public class Test { 
    private static class TestAction extends RecursiveAction { 
     private int i; 

     public TestAction(int i) { 
      this.i = i; 
     } 

     protected void compute() { 
      if (i == 0) { 
       invokeAll(new TestAction(1), new TestAction(2), new TestAction(3), 
          new TestAction(4), new TestAction(5), new TestAction(6)); 
       return; 
      }    
      System.out.println(i + " start"); 
      try { Thread.sleep(2000); } catch (Exception e) { } 
      System.out.println(i + " end"); 
     } 
    }  

    public static void main(String[] args) { 
     new ForkJoinPool().invoke(new TestAction(0)); 
    } 
}  

的與參考Oracle實施運行的結果是:

1 start 
6 start <- wait 2 seconds 
1 end 
2 start 
6 end 
5 start <- wait 2 seconds 
2 end 
3 start 
5 end 
4 start <- wait 2 seconds 
4 end 
3 end 

同樣的行爲是在Linux和Mac OS X一致。

所以這個問題的答案是:是的,這些任務將在並行性參數指定的CPU數量(或默認的總可用CPU數量)上執行。如果CPU時間變得可用並且任務只是阻止等待某事,那麼框架將不會自動執行其他任務。

由於到目前爲止我見過的文檔對於框架在CPU空閒時應該做什麼非常模糊,這可能是一個實現細節。

5

如果不包括你自己,沒有人會被應用於任何限制和Java將叉儘可能多儘可能的線程(可能全部取決於系統限制)。這並不理想。如果你正在做一個計算,它可能有一些IO時間,但即使在大量的併發處理中也不會被IO限制,你可能可以證明運行一個線程,然後運行可用數量的CPU。一次運行1000個並不明智。

如果我有2個CPU併爲fork/join框架安排1000個任務,每次最多執行2個任務,還是同時執行更多任務並行執行中央處理器?

如果你有一個雙核CPU,你只能一次執行2個線程。

+0

那麼框架是否會自動調整可用的資源並自動並行運行更少或更多的任務?例如,如果2個任務只是在等待某件事情,那麼在此期間是否會自動運行其他兩個任務? – rid 2012-07-06 21:29:32

+0

如果您分叉1000次,它將嘗試(也可能失敗)創建1000個線程。另外,創建線程非常昂貴,請考慮做一些重量更輕的事情,比如使用固定大小的線程池以及由Runnable組成的工作單元池。當新線程創建或者新線程啓動時,當前線程是否繼續運行是特定於環境的。但是,假設試圖一次創建1000個線程是一個不好的主意。 – Wug 2012-07-06 22:05:32

+0

謝謝,但這並沒有回答這個問題。 – rid 2012-07-06 22:13:33

1

是對CPU的超線程?如果是這樣,你可以同時運行2+進程。

超線程通過複製處理器的某些部分(存儲架構狀態的部分)而工作,但不復制主執行資源。這允許超線程處理器作爲主機操作系統的兩個「邏輯」處理器出現,允許操作系統同時調度兩個線程或進程。

+0

這也不回答問題。問題是如果一個正在運行的線程被阻塞等待某些事情會發生什麼。在那種情況下,框架產生一個新的工作,而阻塞的人等待,或什麼都不做? – rid 2012-07-06 22:21:26

3

根據the ForkJoin documentation

甲ForkJoinPool被構造成具有給定的目標的平行的水平; 默認情況下,等於可用處理器的數量。池試圖通過 保持足夠的活動(或有)線程動態添加,掛起,或恢復內部工作線程, 即使一些任務都停止等待加入別人。但是,面對被阻塞的IO或其他的非託管同步,這樣的調整是保證的。

所以它可能會在你的2個CPU上一次運行兩個,如果CPU是超線程的(我不確定),可能一次只運行4個。如果您對默認的並行級別不滿意,則可以通過調用將並行級別作爲參數的ForkJoinPool構造函數來指定所請求的並行級別。

+0

您無法爲目標提供大於可用CPU數量的目標。然而,這與我正在尋找的答案非常接近。但是我沒有看到一個明確的聲明,說明如果一個線程停滯,池是否會運行* new *線程。 「池通過動態地添加,暫停或恢復內部工作線程來嘗試維護足夠的活動(或可用)線程」< - 我想知道是否「足夠」它們意味着目標級別(所以如果目標是2,並且1是拖延,產生一個新的運行,直到失速的恢復)。 – rid 2012-07-06 22:19:35

+0

啊,文檔只說並行度不能設置爲大於「實現限制」的值。我沒有意識到這與處理器數量的默認值相同。至於它如何處理阻塞線程,目前尚不清楚,但我認爲'ForkJoinPool.ManagedBlocker'類與它有關。我不確定。我還要指出,源代碼在JDK中可用,雖然它相當複雜。祝你好運。 – 2012-07-07 21:30:02

+0

好吧,如果文檔沒有明確說出任何內容,那麼這取決於運行代碼的任何實現。顯然,參考實現並沒有做任何事情來自動調度新的工作,而CPU空閒。 – rid 2012-07-07 22:35:50

0

默認情況下,Fork/Join Framework會嘗試維持等於比核心數少一個的線程數(如果單個核心機器,然後創建一個線程)。您可以在ForkJoinPool類中的makeCommonPool方法中看到此代碼。

如果您認爲此功能未充分利用您的CPU,則可以爲parallelism提供自定義值。

但最有趣的是,噹噹前線程佔用IO上的CPU塊時,有一種方法可以使ForkJoinPool創建更多線程。您只需要實現在ForkJoinPool.ManagedBlocker對象的block方法的實現中實際阻塞IO的代碼塊,並將ManagedBlocker對象傳遞給ForkJoinPool類的managedBlock方法。完成後,ForkJoinPool將檢查當前調用此方法的線程是否爲ForkJoinPoolWorkerThread的實例。如果是這樣,ForkjoinPool通過創建可以接管CPU的新線程進行補償。

ForkJoinPool fjp = ForkJoinPool.common(); 
Runnable task = new Runnable(){ 
    public void run(){ 
    //Some cpu-intensive code 
    ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker(){ 
     public boolean isReleasable(){ 
     //return true if an IO/blocking operation is to be done. 
     } 

     public boolean block(){ 
     //Do an IO Operation here 
     //return true if all blocking code has finished execution. 
     //return false if more blocking code is yet to execute. 
     } 

    }); 
    //Some more CPU intensive code here 
    } 
}; 
fjp.submit(task);