2011-04-12 30 views
41

當測量經過時間處於低水平,我有使用任何這些的選擇:時間測量的開銷在Java中

System.currentTimeMillis(); 
System.nanoTime(); 

兩種方法實現native。在深入研究任何C代碼之前,有沒有人知道是否有任何實質性開銷調用其中一個或另一個?我的意思是,如果我不真正關心額外的精度,哪一個預計會減少CPU時間?

N.B:我使用的是標準的Java JDK 1.6,但問題可能是任何有效的JRE ...

+1

請注意,'nanoTime'不會映射到實時,只能用於測量所花費的時間。 – Powerlord 2011-04-12 19:31:11

+0

@ R.Bemrose,謝謝,我知道。這真的是測量一些東西需要多長時間。 – 2011-04-12 19:40:04

回答

25

我不相信你需要擔心的任何開銷。它非常小,幾乎不可測量。下面是兩者的快速微基準:

for (int j = 0; j < 5; j++) { 
    long time = System.nanoTime(); 
    for (int i = 0; i < 1000000; i++) { 
     long x = System.currentTimeMillis(); 
    } 
    System.out.println((System.nanoTime() - time) + "ns per million"); 

    time = System.nanoTime(); 
    for (int i = 0; i < 1000000; i++) { 
     long x = System.nanoTime(); 
    } 
    System.out.println((System.nanoTime() - time) + "ns per million"); 

    System.out.println(); 
} 

而最後的結果是:

14297079ns per million 
29206842ns per million 

但看來System.currentTimeMillis()是快兩倍System.nanoTime()。然而,29ns將比任何你測量的東西都短得多。由於它與時鐘無關,因此我會爲System.nanoTime()提供精確度和準確度。

+1

不錯的基準。在我的電腦上,這是相反的。我得到這樣的結果:每百萬17258920ns,百萬14974586ns。這意味着它真的取決於JVM,處理器,操作系統等。除此之外,差別幾乎是不相關的。謝謝你的好回答! – 2011-04-12 19:35:53

+0

沒問題。是的,我確定有各種各樣的因素會使它變化。無論哪種方式,它似乎你必須在現代機器上每秒鐘調用它數百萬次,因爲它會導致明顯的時間開銷。 – WhiteFang34 2011-04-12 19:40:10

+0

基本的操作系統會很有趣。我懷疑如果實現使用POSIX的'clock_gettime()',那麼差異將是〜0。 – ninjalj 2011-04-12 19:40:39

6

System.currentTimeMillis()通常非常快(afaik 5-6 cpu週期,但我不知道我在哪裏閱讀過這些),但它的分辨率因不同平臺而異。

所以如果你需要高精度去nanoTime(),如果你擔心開銷去currentTimeMillis()

+0

好點。檢查WhiteFang34的答案。它們看起來速度相當快,取決於用於對它們進行基準測試的系統。 – 2011-04-12 19:39:18

11

您應該只使用System.nanoTime()來測量需要運行的時間。這不僅僅是納秒精度的問題,System.currentTimeMillis()是「掛鐘時間」,而System.nanoTime()是用於計時的事情,並沒有其他的「真實世界時間」的怪癖。來自System.nanoTime()的Javadoc:

此方法只能用於測量已用時間並且與系統或掛鐘時間的任何其他概念無關。

+0

是的,我知道Javadoc提到了這一點。但是如果你測量的次數在1-10ms之間,兩者都可以等效使用。 「真實世界時間怪癖」是什麼意思? – 2011-04-12 19:31:30

+3

@Lukas:問題是'System.currentTimeMillis()'可以(我相信)做一些事情,比如插入小時鐘調整,這會導致計時。很少見,但'nanoTime()'適用於不應受此類事物影響的測量。 – ColinD 2011-04-12 19:37:33

+0

這很有道理 – 2011-04-12 19:43:23

2

從理論上講,對於使用本地線程,並擔任現代先發制人的操作系統上的虛擬機時,的currentTimeMillis可以實現爲每時間片只讀取一次。據推測,nanoTime實現不會犧牲精度。

+0

這是關於精度的一個好處。如果你是對的,那麼'currentTimeMillis()'不能更精確。或者因爲它不需要很精確,可以通過這種方式實施。但另一方面,這並沒有說哪一個更快...... – 2011-04-12 19:45:36

6

如果您有時間,請看this talk by Cliff Click,他會說System.currentTimeMillis以及其他東西的價格。

+0

不錯,謝謝。我會研究它 – 2011-04-13 06:48:46

39

在此頁面上標記爲正確的答案實際上是不正確的。由於JVM無效代碼消除(DCE),堆棧替換(OSR),循環展開等原因,這不是一種有效的編寫基準的方法。只有Oracle的JMH微型基準測試框架等框架可以正確測量。如果您對這些微基準的有效性有任何疑問,請閱讀this post

這裏是江鈴控股基準System.currentTimeMillis() VS System.nanoTime()

@BenchmarkMode(Mode.AverageTime) 
@OutputTimeUnit(TimeUnit.NANOSECONDS) 
@State(Scope.Benchmark) 
public class NanoBench { 
    @Benchmark 
    public long currentTimeMillis() { 
     return System.currentTimeMillis(); 
    } 

    @Benchmark 
    public long nanoTime() { 
    return System.nanoTime(); 
    } 
} 

而且這裏的結果(在I​​ntel酷睿i5):

Benchmark       Mode Samples  Mean Mean err Units 
c.z.h.b.NanoBench.currentTimeMillis avgt  16 122.976  1.748 ns/op 
c.z.h.b.NanoBench.nanoTime   avgt  16 117.948  3.075 ns/op 

這都說明System.nanoTime()稍快的〜相較於〜123ns,每調用118ns。但是,同樣清楚的是,一旦將平均誤差考慮在內,兩者之間幾乎沒有差別。結果也可能因操作系統而異。但總的來說應該是它們在開銷方面基本上是等價的。

UPDATE 2015/08/25:雖然這個答案更接近正確,大多數使用JMH來衡量,但它仍然是不正確的。測量像System.nanoTime()本身是一種特殊的扭曲基準測試。答案和權威文章是here

+0

精彩的JMH使用!我希望這個網站上的更多微觀基準利用了它。 – 2015-06-20 19:29:19

+0

我想試試你的例子,並想知道爲什麼'@ GenerateMicroBenchmark'註解不起作用。它似乎已經或多或少地最近重新命名爲「@ Benchmark」。 – dajood 2016-07-07 10:19:20

+0

我編輯關注你,@dajood – Oliv 2017-04-13 08:12:23

4

這個問題接受的答案確實是不正確的。 @brettw提供的替代答案雖然不錯,但仍然很注重細節。

對於一個完整的處理這個問題和這些調用的實際成本的,請參閱https://shipilev.net/blog/2014/nanotrusting-nanotime/

要回答這個問的問題:

沒有人知道是否有任何實質性的開銷調用一個或另一個?

  • 主叫System#nanoTime的開銷是每次呼叫15到30毫微秒之間。
  • 通過nanoTime報告的價值,它的分辨率,只改變一次每30納秒

這意味着這取決於你正在試圖做的每秒請求萬元,調用nanoTime意味着你失去有效巨大第二次撥打nanoTime。對於這種用例,考慮從客戶端測量請求,從而確保您不會陷入coordinated omission,測量隊列深度也是一個很好的指標。

如果你不想在一秒鐘內完成儘可能多的工作,那麼nanoTime不會真的很重要,但協調省略仍然是一個因素。

最後,爲了完整起見,currentTimeMillis無論成本如何都不能使用。這是因爲不能保證在兩次通話之間前進。特別是在配備NTP的服務器上,currentTimeMillis正在不斷移動。更不用說,計算機測得的大部分東西都不需要一整毫秒。

+0

感謝您的反饋意見。在此期間,我也偶然發現了阿列克謝·希皮利耶夫的那篇文章。您是否介意以Stack Overflow的精神(這是一個完整的答案,可能由Stack Overflow的鏈接中的更多詳細信息直接支持)的精神將該文章的精髓作爲對具體Stack Overflow問題的回答?那麼我會接受你的答案。 – 2016-11-20 16:05:21

+0

我沒有這樣做以獲得接受的答案。最終的問題是,接受的答案是指導人們走向不合適的錯誤方向。 – pjulien 2016-11-20 17:32:28

+0

自問你就更新了,但同樣的,我總覺得像這樣的答案StackOverflow只是要求麻煩,因爲他們總是留下太多的解釋空間 – pjulien 2016-11-20 18:27:33