日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

慌!还不了解Java中的分支预测?!

發布時間:2024/4/11 java 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 慌!还不了解Java中的分支预测?! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

點擊上方“朱小廝的博客”,選擇“設為星標”

后臺回復”1024“獲取公眾號專屬1024GB資料

來源:rrd.me/fLHvf

1.引言

分支預測是計算機科學中一個有趣的概念,它對我們的應用程序性能會產生深刻的影響。然而,這個概念通常沒有得到很好地理解,大多數開發者對此很少關注。

本文中,我們將探索分支預測的確切含義,如何對軟件產生影響,以及我們可以采取的行動。

2.什么是指令流水線?

開發計算機程序,本質上是編寫一組期望計算機順序執行的命令。

早期的計算機一次僅執行一條命令。這意味著每個命令都會加載到內存中,執行完成后再加載下一個命令。

指令流水線是一種改進。處理器會將工作分解成多個部分,對不同的部分并行執行。這樣,處理器能夠在加載下一條的同時執行一條命令。

處理器內部的指令流水線越長,不僅可以簡化還能并行執行更多的部分。這樣能夠提高系統的整體性能。

例如下面這個簡單的程序:

int a = 0; a += 1; a += 2; a += 3;

程序會按照下面的流水線處理:Fetch(提取)、Decode(解碼)、Execute(執行)、Store(存儲):

這里可以看到四個命令如何并行處理,整體執行速度更快。

3.有什么危害?

處理器執行某些命令時會導致流水線問題流水線中部分指令執行時依賴于之前的指令,但是前面的指令可能還沒有執行。

分支是一種危險。分支會挑選兩個執行方向之一執行,但只有在解析后才能確定是哪個方向。這意味著通過分支加載命令都是不安全的,因為無法知道從哪里加載命令

修改上面的程序加入分支:

int a = 0; a += 1; if (a < 10) {a += 2; } a += 3;

運行結果與之前相同,但其中加入了 if語句。在解析前,雖然計算機能看到這些指令,但不能加載 if 后面的指令。因此,執行的順序看起來像下面這樣:

現在可以立刻看到加入分支對程序執行造成的影響,得到相同結果所需的時鐘周期。

4.什么是分支預測?

分支預測是對上面的一種改進,計算機會嘗試預測分支的執行路徑,然后采取相應的動作。

在上面的示例中,處理器會預測if(a <10)為 true,因此把 a += 2 作為下一條待執行指令。這將導致執行的順序變成這樣:

可以看到程序的性能立即得到了提升:現在只要9個時鐘周期而不是之前的11個,速度提升了19%。

但是,這樣做也并非沒有風險。如果分支預測出錯,那么將對不應該執行的指令排隊。發生這種情況時,計算機要丟棄這些指令重新開始。

修改判斷條件改為false:

int a = 0; a += 1; if (a > 10) {a += 2; } a += 3;

可能會像下面這樣執行:

現在,即使處理的指令更少,執行卻比之前慢!處理器錯誤地預測分支等于 true,把 a += 2 指令排隊。接著發現分支等于 false,必須丟棄已排隊的指令,然后重新執行。

5.對實際代碼的影響

現在我們知道分支預測的概念及優點,那么對實際代碼有什么影響?畢竟,這里討論的是在高速運行的計算機上損失幾個時鐘周期,影響肯定不會那么明顯。

有時候的確如此。但也有一些情況會對應用程序性能帶來顯著影響。很大程度上取決于進行的工作。具體來說,與在短時間內需要完成的工作有關。

5.1.統計列表條目

讓我們試著統計列表中的條目。接下來會生成一個數字列表,然后統計其中有多少個數字小于臨界值。與上面的示例類似,但是用循環取代了單個指令:

List<Long> numbers = LongStream.range(0, top).boxed().collect(Collectors.toList());if (shuffle) {Collections.shuffle(numbers); }long cutoff = top / 2; long count = 0;long start = System.currentTimeMillis(); for (Long number : numbers) {if (number < cutoff) {++count;} } long end = System.currentTimeMillis();LOG.info("Counted {}/{} {} numbers in {}ms",count, top, shuffle ? "shuffled": "sorted", end - start);

請注意,這里只對計數循環計時,因為這才我們感興趣的工作。那么需要多少時間呢?

如果生成的列表較小,那么代碼執行很快,無法統計:10萬條數據的列表執行結果為0毫秒。但是當列表足夠大時,可以看到計時結果中 shuffle 條件對結果有顯著影響。包含1000萬個數字的列表:

  • Sorted – 44ms

  • Shuffled – 221ms

也就是說,即使計算的數據相同,隨機(shuffled)列表用時是排序后的5倍。

但是,排序操作本身的開銷比計數要大得多。我們應該分析自己的代碼,確定是否有性能提升的空間。

5.2.分支順序

從上面的內容可以看出,if/else 語句的分支順序很重要。也就是說,下面這樣的分支安排性能會更好:

if (mostLikely) {// Do something } else if (lessLikely) {// Do something } else if (leastLikely) {// Do something }

然而,現代計算機可以通過分支預測緩存來避免這個問題。實際上,也可以對此進行測試:

List<Long> numbers = LongStream.range(0, top).boxed().collect(Collectors.toList()); if (shuffle) {Collections.shuffle(numbers); }long cutoff = (long)(top * cutoffPercentage); long low = 0; long high = 0;long start = System.currentTimeMillis(); for (Long number : numbers) {if (number < cutoff) {++low;} else {++high;} } long end = System.currentTimeMillis();LOG.info("Counted {}/{} numbers in {}ms", low, high, end - start);

計算1000萬個數字時,無論 cutoffPercentage 如何設置,代碼執行的結果基本一致:排序數字約35毫秒,隨機數字約200毫秒。

這是因為分支預測器會平等地處理兩個分支,并正確猜測我們將采用其中哪一個。

5.3.合并條件

使用一個條件和兩個條件有什么區別?相同的結果可以用不同方式重寫實現邏輯,是否應該這樣做?

例如,可以用兩個數字分別與0比較,也可以用兩個數字的乘積與0比較。用乘法代替條件。這種做法是否值得?

讓我們考慮下面這個例子:

long[] first = LongStream.range(0, TOP).map(n -> Math.random() < FRACTION ? 0 : n).toArray(); long[] second = LongStream.range(0, TOP).map(n -> Math.random() < FRACTION ? 0 : n).toArray();long count = 0; long start = System.currentTimeMillis(); for (int i = 0; i < TOP; i++) {if (first[i] != 0 && second[i] != 0) {++count;} } long end = System.currentTimeMillis();LOG.info("Counted {}/{} numbers using separate mode in {}ms", count, TOP, end - start);

像上面這樣,循環中的條件可以替換。實際上這樣做會影響結果:

  • 分開條件– 40ms

  • 單個條件(乘法)– 22ms

因此,使用兩個分開的條件實際的時間開銷是單個條件的兩倍。

6.總結

我們已經了解了什么是分支預測及其如何對程序產生影響。這樣我們又掌握了一個工具,保證程序盡可能高效。

盡管如此,在進行重大變更前,我們仍然需要一如既往地對代碼進行性能分析。有時不合理的分支條件可能會帶來更大的開銷。

本文的示例可以在GitHub上找到。

github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-perf

想知道更多?描下面的二維碼關注我

【精彩推薦】

  • 混沌工程初識

  • 混沌工程的陷阱

  • Spring Boot 服務監控,健康檢查,線程信息,JVM堆信息,指標收集,運行情況監控等!

  • 中國頂級互聯網公司的技術組織架構調整預示著什么?

朕已閱?

總結

以上是生活随笔為你收集整理的慌!还不了解Java中的分支预测?!的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。