<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ### [JMH 的引入](https://lingcoder.gitee.io/onjava8/#/book/16-Validating-Your-Code?id=jmh-%e7%9a%84%e5%bc%95%e5%85%a5) 截止目前為止,唯一能產生像樣結果的 Java 微基準測試系統就是 Java Microbenchmarking Harness,簡稱 JMH。本書的**build.gradle**自動引入了 JMH 的設置,所以你可以輕松地使用它。 你可以在命令行編寫 JMH 代碼并運行它,但是推薦的方式是讓 JMH 系統為你運行測試;**build.gradle**文件已經配置成只需要一條命令就能運行 JMH 測試。 JMH 嘗試使基準測試變得盡可能簡單。例如,我們將使用 JMH 重新編寫**BadMicroBenchmark.java**。這里只有**@State**和**@Benchmark**這兩個注解是必要的。其余的注解要么是為了產生更多易懂的輸出,要么是加快基準測試的運行速度(JMH 基準測試通常需要運行很長時間): ~~~ // validating/jmh/JMH1.java package validating.jmh; import java.util.*; import org.openjdk.jmh.annotations.*; import java.util.concurrent.TimeUnit; @State(Scope.Thread) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) // Increase these three for more accuracy: @Warmup(iterations = 5) @Measurement(iterations = 5) @Fork(1) public class JMH1 { private long[] la; @Setup public void setup() { la = new long[250_000_000]; } @Benchmark public void setAll() { Arrays.setAll(la, n -> n); } public void parallelSetAll() { Arrays.parallelSetAll(la, n -> n); } } ~~~ “forks” 的默認值是 10,意味著每個測試都運行 10 次。為了減少運行時間,這里使用了**@Fork**注解來減少這個次數到 1。我還使用了**@Warmup**和**@Measurement**注解將它們默認的運行次數從 20 減少到 5 次。盡管這降低了整體的準確率,但是結果幾乎與使用默認值相同。可以嘗試將**@Warmup**、\*\*@Measurement\*\* 和**@Fork**都注釋掉然后看使用它們的默認值,結果會有多大顯著的差異;一般來說,你應該只能看到長期運行的測試使錯誤因素減少,而結果沒有多大變化。 需要使用顯式的 gradle 命令才能運行基準測試(在示例代碼的根目錄處運行)。這能防止耗時的基準測試運行其他的**gradlew**命令: **gradlew validating:jmh** 這會花費幾分鐘的時間,取決于你的機器(如果沒有注解上的調整,可能需要幾個小時)。控制臺會顯示**results.txt**文件的路徑,這個文件統計了運行結果。注意,**results.txt**包含這一章所有**jmh**測試的結果:**JMH1.java**,**JMH2.java**和**JMH3.java**。 因為輸出是絕對時間,所以在不同的機器和操作系統上結果各不相同。重要的因素不是絕對時間,我們真正觀察的是一個算法和另一個算法的比較,尤其是哪一個運行得更快,快多少。如果你在自己的機器上運行測試,你將看到不同的結果卻有著相同的模式。 我在大量的機器上運行了這些測試,盡管不同的機器上得到的絕對值結果不同,但是相對值保持著合理的穩定性。我只列出了**results.txt**中適當的片段并加以編輯使輸出更加易懂,而且內容大小適合頁面。所有測試中的**Mode**都以**avgt**展示,代表 “平均時長”。**Cnt**(測試的數目)的值是 200,盡管這里的一個例子中配置的**Cnt**值是 5。**Units**是**us/op**,是 “Microseconds per operation” 的縮寫,因此,這個值越小代表性能越高。 我同樣也展示了使用 warmups、measurements 和 forks 默認值的輸出。我刪除了示例中相應的注解,就是為了獲取更加準確的測試結果(這將花費數小時)。結果中數字的模式應該仍然看起來相同,不論你如何運行測試。 下面是**JMH1.java**的運行結果: **Benchmark Score** **JMH1.setAll 196280.2** **JMH1.parallelSetAll 195412.9** 即使像 JMH 這么高級的基準測試工具,基準測試的過程也不容易,練習時需要倍加小心。這里測試產生了反直覺的結果:并行的版本**parallelSetAll()**花費了與非并行版本的**setAll()**相同的時間,兩者似乎都運行了相當長的時間。 當創建這個示例時,我假設如果我們要測試數組初始化的話,那么使用非常大的數組是有意義的。所以我選擇了盡可能大的數組;如果你實驗的話會發現一旦數組的大小超過 2億5000萬,你就開始會得到內存溢出的異常。然而,在這么大的數組上執行大量的操作從而震蕩內存系統,產生無法預料的結果是有可能的。不管這個假設是否正確,看上去我們正在測試的并非是我們想測試的內容。 考慮其他的因素: C:客戶端執行操作的線程數量 P:并行算法使用的并行數量 N:數組的大小:\**10^(2*k)**,通常來說,**k=1..7\*\* 足夠來練習不同的緩存占用。 Q:setter 的操作成本 這個 C/P/N/Q 模型在早期 JDK 8 的 Lambda 開發期間浮出水面,大多數并行的 Stream 操作(**parallelSetAll()**也基本相似)都滿足這些結論:\**N*Q\*\*(主要工作量)對于并發性能尤為重要。并行算法在工作量較少時可能實際運行得更慢。 在一些情況下操作競爭如此激烈使得并行毫無幫助,而不管 \**N*Q\*\* 有多大。當**C**很大時,**P**就變得不太相關(內部并行在大量的外部并行面前顯得多余)。此外,在一些情況下,并行分解會讓相同的**C**個客戶端運行得比它們順序運行代碼更慢。 基于這些信息,我們重新運行測試,并在這些測試中使用不同大小的數組(改變**N**): ~~~ // validating/jmh/JMH2.java package validating.jmh; import java.util.*; import org.openjdk.jmh.annotations.*; import java.util.concurrent.TimeUnit; @State(Scope.Thread) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @Warmup(iterations = 5) @Measurement(iterations = 5) @Fork(1) public class JMH2 { private long[] la; @Param({ "1", "10", "100", "1000", "10000", "100000", "1000000", "10000000", "100000000", "250000000" }) int size; @Setup public void setup() { la = new long[size]; } @Benchmark public void setAll() { Arrays.setAll(la, n -> n); } @Benchmark public void parallelSetAll() { Arrays.parallelSetAll(la, n -> n); } } ~~~ **@Param**會自動地將其自身的值注入到變量中。其自身的值必須是字符串類型,并可以轉化為適當的類型,在這個例子中是**int**類型。 下面是已經編輯過的結果,包含精確計算出的加速數值: | JMH2 Benchmark | Size | Score % | Speedup | | --- | --- | --- | --- | | **setAll** | 1 | 0.001 | | | **parallelSetAll** | 1 | 0.036 | 0.028 | | **setAll** | 10 | 0.005 | | | **parallelSetAll** | 10 | 3.965 | 0.001 | | **setAll** | 100 | 0.031 | | | **parallelSetAll** | 100 | 3.145 | 0.010 | | **setAll** | 1000 | 0.302 | | | **parallelSetAll** | 1000 | 3.285 | 0.092 | | **setAll** | 10000 | 3.152 | | | **parallelSetAll** | 10000 | 9.669 | 0.326 | | **setAll** | 100000 | 34.971 | | | **parallelSetAll** | 100000 | 20.153 | 1.735 | | **setAll** | 1000000 | 420.581 | | | **parallelSetAll** | 1000000 | 165.388 | 2.543 | | **setAll** | 10000000 | 8160.054 | | | **parallelSetAll** | 10000000 | 7610.190 | 1.072 | | **setAll** | 100000000 | 79128.752 | | | **parallelSetAll** | 100000000 | 76734.671 | 1.031 | | **setAll** | 250000000 | 199552.121 | | | **parallelSetAll** | 250000000 | 191791.927 | 1.040 | | 可以看到當數組大小達到 10 萬左右時,**parallelSetAll()**開始反超,而后趨于與非并行的運行速度相同。即使它運行速度上勝了,看起來也不足以證明由于并行的存在而使速度變快。 | | | | **setAll()/parallelSetAll()**中工作的計算量起很大影響嗎?在前面的例子中,我們所做的只有對數組的賦值操作,這可能是最簡單的任務。所以即使**N**值變大,\**N*Q\*\* 也仍然沒有達到巨大,所以看起來像是我們沒有為并行提供足夠的機會(JMH 提供了一種模擬變量 Q 的途徑;如果想了解更多的話,可搜索**Blackhole.consumeCPU**)。 我們通過使方法**f()**中的任務變得更加復雜,從而產生更多的并行機會: ~~~ // validating/jmh/JMH3.java package validating.jmh; import java.util.*; import org.openjdk.jmh.annotations.*; import java.util.concurrent.TimeUnit; @State(Scope.Thread) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @Warmup(iterations = 5) @Measurement(iterations = 5) @Fork(1) public class JMH3 { private long[] la; @Param({ "1", "10", "100", "1000", "10000", "100000", "1000000", "10000000", "100000000", "250000000" }) int size; @Setup public void setup() { la = new long[size]; } public static long f(long x) { long quadratic = 42 * x * x + 19 * x + 47; return Long.divideUnsigned(quadratic, x + 1); } @Benchmark public void setAll() { Arrays.setAll(la, n -> f(n)); } @Benchmark public void parallelSetAll() { Arrays.parallelSetAll(la, n -> f(n)); } } ~~~ **f()**方法提供了更加復雜且耗時的操作。現在除了簡單的給數組賦值外,**setAll()**和**parallelSetAll()**都有更多的工作去做,這肯定會影響結果。 | JMH2 Benchmark | Size | Score % | Speedup | | --- | --- | --- | --- | | **setAll** | 1 | 0.012 | | | **parallelSetAll** | 1 | 0.047 | 0.255 | | **setAll** | 10 | 0.107 | | | **parallelSetAll** | 10 | 3.894 | 0.027 | | **setAll** | 100 | 0.990 | | | **parallelSetAll** | 100 | 3.708 | 0.267 | | **setAll** | 1000 | 133.814 | | | **parallelSetAll** | 1000 | 11.747 | 11.391 | | **setAll** | 10000 | 97.954 | | | **parallelSetAll** | 10000 | 37.259 | 2.629 | | **setAll** | 100000 | 988.475 | | | **parallelSetAll** | 100000 | 276.264 | 3.578 | | **setAll** | 1000000 | 9203.103 | | | **parallelSetAll** | 1000000 | 2826.974 | 3.255 | | **setAll** | 10000000 | 92144.951 | | | **parallelSetAll** | 10000000 | 28126.202 | 3.276 | | **setAll** | 100000000 | 921701.863 | | | **parallelSetAll** | 100000000 | 266750.543 | 3.455 | | **setAll** | 250000000 | 2299127.273 | | | **parallelSetAll** | 250000000 | 538173.425 | 4.272 | 可以看到當數組的大小達到 1000 左右時,**parallelSetAll()**的運行速度反超了**setAll()\*\*。看來 \*\*parallelSetAll()**嚴重依賴數組中計算的復雜度。這正是基準測試的價值所在,因為我們已經得到了關于**setAll()**和**parallelSetAll()**間微妙的信息,知道在何時使用它們。 這顯然不是從閱讀 Javadocs 就能得到的。 大多數時候,JMH 的簡單應用會產生好的結果(正如你將在本書后面例子中所見),但是我們從這里知道,你不能一直假定 JMH 會產生好的結果。 JMH 網站上的范例可以幫助你開始。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看