循环内的局部变量和性能
總覽
有時會出現一個問題,即分配一個新的局部變量需要花費多少工作。 我的感覺一直是,代碼已優化到成本為靜態的程度,即一次執行,而不是每次運行時都執行。
最近, Ishwor Gurung建議考慮將一些局部變量移出循環。 我懷疑這不會有所作為,但我從未測試過是否確實如此。
考試
這是我運行的測試:
public static void main(String... args) {for (int i = 0; i < 10; i++) {testInsideLoop();testOutsideLoop();} }private static void testInsideLoop() {long start = System.nanoTime();int[] counters = new int[144];int runs = 200 * 1000;for (int i = 0; i < runs; i++) {int x = i % 12;int y = i / 12 % 12;int times = x * y;counters[times]++;}long time = System.nanoTime() - start;System.out.printf("Inside: Average loop time %.1f ns%n", (double) time / runs); }private static void testOutsideLoop() {long start = System.nanoTime();int[] counters = new int[144];int runs = 200 * 1000, x, y, times;for (int i = 0; i < runs; i++) {x = i % 12;y = i / 12 % 12;times = x * y;counters[times]++;}long time = System.nanoTime() - start;System.out.printf("Outside: Average loop time %.1f ns%n", (double) time / runs); }輸出以以下結尾:
內部 :平均循環時間3.6 ns
外 :平均循環時間3.6 ns
內部 :平均循環時間3.6 ns 外 :平均循環時間3.6 ns
將測試時間增加到1億次迭代,對結果的影響很小。
內部 :平均循環時間3.8 ns
外 :平均循環時間3.8 ns
內部 :平均循環時間3.8 ns 外 :平均循環時間3.8 ns
用>>, &, + I代替模和乘法
int x = i & 15; int y = (i >> 4) & 15; int times = x + y;版畫
內部 :平均循環時間1.2 ns
外 :平均循環時間1.2 ns
內部 :平均循環時間1.2 ns 外 :平均循環時間1.2 ns
盡管模量相對昂貴,但測試的分辨率為0.1 ns或小于時鐘周期的1/3。 這將顯示兩次測試之間的任何差異,以達到此精度。
使用卡尺
正如@maaartinus所評論的那樣, Caliper是一個微基準測試庫,因此我對手工編寫代碼可能會慢得多感興趣。
public static void main(String... args) {Runner.main(LoopBenchmark.class, args); }public static class LoopBenchmark extends SimpleBenchmark {public void timeInsideLoop(int reps) {int[] counters = new int[144];for (int i = 0; i < reps; i++) {int x = i % 12;int y = i / 12 % 12;int times = x * y;counters[times]++;}}public void timeOutsideLoop(int reps) {int[] counters = new int[144];int x, y, times;for (int i = 0; i < reps; i++) {x = i % 12;y = i / 12 % 12;times = x * y;counters[times]++;}} }首先要注意的是,代碼較短,因為它不包括計時和印刷樣板代碼。 運行此程序,我將與第一個測試使用同一臺計算機。
0% Scenario{vm=java, trial=0, benchmark=InsideLoop} 4.23 ns; σ=0.01 ns @ 3 trials 50% Scenario{vm=java, trial=0, benchmark=OutsideLoop} 4.23 ns; σ=0.01 ns @ 3 trialsbenchmark?? ns linear runtime InsideLoop 4.23 ============================== OutsideLoop 4.23 =============================vm: java trial: 0用shift和and替換模數
0% Scenario{vm=java, trial=0, benchmark=InsideLoop} 1.27 ns; σ=0.01 ns @ 3 trials 50% Scenario{vm=java, trial=0, benchmark=OutsideLoop} 1.27 ns; σ=0.00 ns @ 3 trialsbenchmark?? ns linear runtime InsideLoop 1.27 ============================= OutsideLoop 1.27 ==============================vm: java trial: 0這與第一個結果是一致的,并且一次測試僅慢了0.4-0.6 ns。 (大約兩個時鐘周期),并且移位幾乎沒有差異,并且加上測試。 這可能是由于游標卡尺對數據進行采樣而不會改變結果的緣故。
毫無疑問,在運行真實程序時,由于微型程序會執行更多操作,因此獲得的時間通常比微型基準測試時間更長,因此緩存和分支預測并不理想。 對所花費時間的一小部分過高估計可能更接近您在實際程序中所期望的時間。
結論
這向我表明,在這種情況下,沒有任何區別。 我仍然懷疑當JIT編譯代碼時分配局部變量的成本不會一次,并且沒有考慮每個迭代的成本。
參考: 可以優化同步嗎? 來自我們的JCG合作伙伴 Peter Lawrey,來自Vanilla Java博客。
翻譯自: https://www.javacodegeeks.com/2012/12/local-variables-inside-a-loop-and-performance.html
總結
以上是生活随笔為你收集整理的循环内的局部变量和性能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 石头推出 2 款 Q 系列扫地机器人,售
- 下一篇: 增加堆大小–谨防眼镜蛇效应