1

我知道有很多因素會影響Java程序的運行時間。我試圖消除其中的一些,其中包括:什麼可能會導致並行Java程序運行時間差異很大?

  • 預熱運行被考慮並且不計算在內。
  • System.gc()在任何兩次運行之間調用。

但我發現數據仍然變化很大。下面是當使用10個線程的例子:

157th run 
0 run time: 9106171 
1 run time: 9084652 
2 run time: 8990820 
3 run time: 8989474 
5 run time: 9062850 
4 run time: 9302010 
9 run time: 9454475 
8 run time: 9506585 
7 run time: 9494990 
6 run time: 9491779 
total time: 31 ms 

158th run 
2 run time: 14754858 
5 run time: 14865035 
0 run time: 15759180 
1 run time: 15988056 
3 run time: 16660592 
8 run time: 16340240 
9 run time: 16544479 
6 run time: 17280122 
7 run time: 17249778 
4 run time: 18026322 
total time: 19 ms 

我發現多數奔跑,他們把像17〜20毫秒,但對於< 5%運行時,他們採取了類似25〜31毫秒。更有趣的是,在後面的情況下,每個線程的運行時間甚至更短,更短

該程序的主線程只有start()join()的線程,並且沒有更多的工作要做。

任何人都可以提供一些想法/提示?

+0

這些線程究竟在做什麼? –

+0

第一次猜測:JIT熱身。第二個猜測:GC(隨着對象的積累,並被掃除)。你已經涵蓋了這些。建議:1)剖析應用程序,2)觀察運行時的堆行爲 – paulsm4

+0

@DavidSchwartz基本上,每個線程處理一個字符串段並生成一個樹數據結構。 – JackWM

回答

1

假設第157次運行,所有線程都在一個內核上運行。瓶頸只是讓他們像時尚一樣排隊等待對方。每個人的跑步都很快,因爲他們對內存資源進行了獨佔統治,但總體來說很慢,因爲他們都排隊等待輪到他們。

假設第158次運行分佈在多個內核中。所有人都會立即競爭內存/緩存資源,因此每個線程都需要更長的時間。但是因爲他們都在同一時間工作,所以整個過程更快完成。

爲了測試這個假設,在運行之間重用一個線程池,並手動設置它們的親和性。

這只是一個可能的解釋,有可能是其他因素,它都是非確定性的。例如,您的操作系統可能同時安排了一些其他程序(例如,cron作業)。

+0

你是什麼意思「但總體來說很慢」?主線程除了創建/銷燬線程外沒有做任何事情。 – JackWM

+0

處理器親和度/操作系統調度可能是相關的 - Daniel Kinsman提出的很好的建議!關於「剖析」,有很多資源。 JConsole是一個很好的開始。請參閱此鏈接:http://www.infoq.com/articles/java-profiling-with-open-source – paulsm4

+0

@JackWM主線程坐在那裏,等待所有其他人完成。這就是'join'的作用。 –

3

我注意到你正在啓動和停止線程。由於測試非常短,這些線程只有時間分配給一個(或少量)cpus排列。這種安排可能意味着更多的線程同時運行,但是使用超線程技術,都會使用核心的cpus。當發生這種情況時,每個線程都會變慢(因爲它必須共享一個內核,緩存等),但吞吐量會隨着線程上下文切換的減少和內核的更高效使用而增加。在另一種安排中,每個內核可能只有一個CPU繁忙,這意味着每個線程更快,但總運行時間更長。

我會嘗試使用一個ExecutorService,使用與您有cpus(或一些多個)相同的數量任務並重新使用這些線程。這會讓你在運行之間更加一致,操作系統將有時間以更有效的方式放置你的線程。

我寫了一個庫,可以讓你分配線程到不同的CPU佈局。例如共享或不共享核心。 https://github.com/peter-lawrey/Java-Thread-Affinity

+0

是的 - 嘗試將線程綁定到內核以提高性能,但是隨後使用開始/連接:(( –

+0

)當有少量關鍵線程存在很長一段時間時,關聯有助於幫助減少不可預測性在測試中也是如此。 –

相關問題