自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

關于四種獲取當前執(zhí)行方法名稱方案的基準測試報告

開發(fā) 前端
根據(jù)最后得分可以看出,四種方案中性能最好的方案是基于匿名內(nèi)部類的 getClass().getEnclosingMethod() 方案,性能第二是的是基于 Java 9 出現(xiàn)的 Stack-Walking API 方案,其他兩種性能過于低下了。

本文是對作者上一篇文章中 Java 面試題之 Logback 打印日志是如何獲取當前方法名稱的? 介紹的四種獲取當前執(zhí)行方法名稱方案的基準測試報告。這四種方法如下,

  1. 使用 Thread.currentThread().getStackTrace() 方案
  2. 使用異常對象的 getStackTrace() 方案
  3. 使用匿名內(nèi)部類的 getClass().getEnclosingMethod() 方案
  4. Java 9 的 Stack-Walking API 方案

本文將通過使用專業(yè)基準測試工具 JMH 來對如上四種方案進行測試。

基準測試,也稱之為性能測試,是一種用于衡量計算機系統(tǒng),軟件應用或硬件組件性能的測試方法?;鶞蕼y試旨在通過運行一系列標準化的任務場景來測量系統(tǒng)的性能表現(xiàn),從而幫助評估系統(tǒng)的各種指標,如響應時間、吞吐量、延遲、資源利用率等。

JMH,即 Java Microbenchmark Harness,是專門用于代碼微基準測試的工具套件。何謂 Micro Benchmark 呢?簡單的來說就是基于方法層面的基準測試,精度可以達到微秒級。其由 Oracle/openjdk 內(nèi)部開發(fā) JIT 編譯器的大佬們所開發(fā),作為 Java 的方法級性能測試工具可以說是非常合適的。

測試環(huán)境是作者 2018 年購買的筆記本,配置如下,

圖片圖片

重點看:

  • cpu:i7-8759H,6 核 12 線程
  • 內(nèi)存 16 GB(2667 MHZ)

前置準備

本文不打算做基準測試工具 JMH 的詳細科普文章,有興趣的大家自行百度 JMH 使用。所以我在這里只給大家講解 JMH 的相關概念以及下文會用到的常用注解。

JMH  可以通過注解和配置參數(shù)來控制測試的環(huán)境和結果,例如預熱次數(shù),迭代次數(shù),線程數(shù),時間單位等。它還可以生成詳細的測試報告,包括最小值,平均值,最大值,標準差,置信區(qū)間等。

JMH 相關概念

  • BeachMark:基準測試,主要用來測試一些方法的性能,可以根據(jù)不同的參數(shù)以不同的單位進行計算(可以使用平均時間作為單位,也可以使用吞吐量作為單位,可以在 BenchmarkMode 值進行調(diào)整)。
  • MIcro Benchmark:簡單地說就是在 method 層面上的 benchmark,精度可以精確到微秒級。
  • OPS:Operation Per Second:每秒操作量,是衡量性能的重要指標,數(shù)值的性能越好。類似的有:TPS、QPS。
  • Throughput:吞吐量。
  • Warmup:預熱,因為 JVM 的 JIT 機制的存儲,如果某個函數(shù)被調(diào)用多次之后,JVM 會嘗試將其編譯稱為機器碼從而提高執(zhí)行速度。為了讓結果更加接近真實情況就需要進行預熱。

JMH 注解介紹

  • @Benchmark:方法級注解,表示該方法是需要進行基準測試的對象,用法和 JUnit 的@Test類似。
  • @BenchmarkMode:類級或方法級注解,用來指定基準測試的模式。有以下幾種模式可選:

Throughput:整體吞吐量,例如“1 秒內(nèi)可以執(zhí)行多少次調(diào)用”。

AverageTime:調(diào)用的平均時間,例如“每次調(diào)用平均耗時 xxx 毫秒”。

SampleTime:隨機取樣,最后輸出取樣結果的分布,例如“99%的調(diào)用在 xxx 毫秒以內(nèi),99.99%的調(diào)用在 xxx 毫秒以內(nèi)”。

SingleShotTime:單次調(diào)用時間,適合用于冷啟動測試,只運行一次,可以設置@Warmup(iterations = 0)來禁用預熱。

All:上述所有模式的綜合。

  • @OutputTimeUnit:類級或方法級注解,用來指定基準測試結果的時間單位,可選的有NANOSECONDS,MICROSECONDS,MILLISECONDS,SECONDS等。
  • @Warmup:類級或方法級注解,用來配置預熱的參數(shù),例如預熱的次數(shù),每次預熱的時間,時間單位等。預熱的目的是為了讓 JVM 的 JIT 編譯器對代碼進行優(yōu)化,使基準測試的結果更加接近真實情況。
  • @Measurement:類級或方法級注解,用來配置實際執(zhí)行基準測試的參數(shù),例如測試的輪次,每輪的時間,時間單位等。
  • @Threads:類級或方法級注解,用來指定每個進程中的測試線程數(shù),可以設置為Threads.MAX來使用所有可用的線程。
  • @Fork:類級或方法級注解,用來指定進行 fork 的次數(shù)。如果 fork 數(shù)是 2 的話,則 JMH 會 fork 出兩個進程來進行測試。

1.使用 Thread.currentThread().getStackTrace() 方法

基準測試參數(shù)配置,

Warmup: 3 iterations, 10 s each
Measurement: 5 iterations, 3 s each
Timeout: 10 min per iteration
Threads: 8 threads, will synchronize iterations
Benchmark mode: Throughput

測試代碼,

需要說明的是下面的四種測試方法的 JMH 注解配置以及 main 方法都是相同的。所以為了節(jié)約篇幅,突出重點,后面三種方案將省去 JMH 注解以及 main 方法配置。

@BenchmarkMode(Mode.Throughput)
@Warmup(iterations = 3)
@Measurement(iterations = 5, time = 3, timeUnit = TimeUnit.SECONDS)
@Threads(8)
@Fork(2)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class MethodNameTest {
    @Benchmark
    @BenchmarkMode({Mode.Throughput})
    public void m1() {
        // 獲取當前方法名
        String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(MethodNameTest.class.getSimpleName())
                .build();

        new Runner(opt).run();
    }
}

測試結果,

...
# Run progress: 0.00% complete, ETA 00:06:00
# Fork: 1 of 2
# Warmup Iteration   1: 16.946 ops/ms
# Warmup Iteration   2: 17.086 ops/ms
# Warmup Iteration   3: 17.116 ops/ms
Iteration   1: 17.159 ops/ms
Iteration   2: 17.118 ops/ms
Iteration   3: 17.279 ops/ms
Iteration   4: 17.329 ops/ms
Iteration   5: 17.241 ops/ms

# Run progress: 12.50% complete, ETA 00:05:23
# Fork: 2 of 2
# Warmup Iteration   1: 16.546 ops/ms
# Warmup Iteration   2: 17.340 ops/ms
# Warmup Iteration   3: 17.431 ops/ms
Iteration   1: 17.331 ops/ms
Iteration   2: 17.099 ops/ms
Iteration   3: 17.280 ops/ms
Iteration   4: 17.511 ops/ms
Iteration   5: 17.323 ops/ms


Result "ltd.newbee.mall.MethodNameTest.m1":
  17.267 ±(99.9%) 0.184 ops/ms [Average]
  (min, avg, max) = (17.099, 17.267, 17.511), stdev = 0.122
  CI (99.9%): [17.083, 17.451] (assumes normal distribution)

上面一大堆輸出信息,大家直接看重點,在最后 Result "ltd.newbee.mall.MethodNameTest.m1": 這里,平均 ops 是每毫秒 17 次,比較低。

2.使用異常對象的 getStackTrace() 方法

測試代碼,

@Benchmark
@BenchmarkMode({Mode.Throughput})
public void m2() {
    // 獲取當前方法名
    String methodName = new Throwable().getStackTrace()[0].getMethodName();
}

測試結果,

...
# Run progress: 25.00% complete, ETA 00:04:37
# Fork: 1 of 2
# Warmup Iteration   1: 12.891 ops/ms
# Warmup Iteration   2: 12.873 ops/ms
# Warmup Iteration   3: 13.023 ops/ms
Iteration   1: 25.617 ops/ms
Iteration   2: 25.840 ops/ms
Iteration   3: 25.301 ops/ms
Iteration   4: 24.839 ops/ms
Iteration   5: 25.930 ops/ms

# Run progress: 37.49% complete, ETA 00:03:51
# Fork: 2 of 2
# Warmup Iteration   1: 12.511 ops/ms
# Warmup Iteration   2: 12.329 ops/ms
# Warmup Iteration   3: 13.011 ops/ms
Iteration   1: 23.842 ops/ms
Iteration   2: 24.292 ops/ms
Iteration   3: 25.600 ops/ms
Iteration   4: 25.745 ops/ms
Iteration   5: 25.789 ops/ms


Result "ltd.newbee.mall.MethodNameTest.m2":
  25.280 ±(99.9%) 1.088 ops/ms [Average]
  (min, avg, max) = (23.842, 25.280, 25.930), stdev = 0.720
  CI (99.9%): [24.191, 26.368] (assumes normal distribution)

直接看最后 Result "ltd.newbee.mall.MethodNameTest.m2": 這里,平均 ops 是每毫秒 25 次,也比較低。

3.使用匿名內(nèi)部類的 getClass().getEnclosingMethod() 方法

測試代碼,

@Benchmark
@BenchmarkMode({Mode.Throughput})
public void m1() {
    // 獲取當前方法名
    String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
}

測試結果,

...
# Run progress: 49.99% complete, ETA 00:03:04
# Fork: 1 of 2
# Warmup Iteration   1: 10489.110 ops/ms
# Warmup Iteration   2: 9233.590 ops/ms
# Warmup Iteration   3: 10504.615 ops/ms
Iteration   1: 10695.898 ops/ms
Iteration   2: 10570.155 ops/ms
Iteration   3: 11089.810 ops/ms
Iteration   4: 10805.448 ops/ms
Iteration   5: 10027.222 ops/ms

# Run progress: 62.49% complete, ETA 00:02:18
# Fork: 2 of 2
# Warmup Iteration   1: 11322.008 ops/ms
# Warmup Iteration   2: 10025.593 ops/ms
# Warmup Iteration   3: 10808.095 ops/ms
Iteration   1: 10684.594 ops/ms
Iteration   2: 11241.540 ops/ms
Iteration   3: 10742.348 ops/ms
Iteration   4: 9940.437 ops/ms
Iteration   5: 11226.023 ops/ms


Result "ltd.newbee.mall.MethodNameTest.m3":
  10702.347 ±(99.9%) 672.631 ops/ms [Average]
  (min, avg, max) = (9940.437, 10702.347, 11241.540), stdev = 444.904
  CI (99.9%): [10029.716, 11374.979] (assumes normal distribution)

直接看最后 Result "ltd.newbee.mall.MethodNameTest.m3": 這里,平均 ops 是每毫秒 10702 次。非常夸張,可以看到 ops 對比上面兩種方法一下子從幾十級別提升到上萬級別。

4.Java 9 的 Stack-Walking API

測試代碼,

@Benchmark
@BenchmarkMode({Mode.Throughput})
public void m1() {
    // 獲取當前方法名
    String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
}

測試結果,

...
# Run progress: 74.99% complete, ETA 00:01:32
# Fork: 1 of 2
# Warmup Iteration   1: 2191.034 ops/ms
# Warmup Iteration   2: 2141.886 ops/ms
# Warmup Iteration   3: 2192.843 ops/ms
Iteration   1: 2262.279 ops/ms
Iteration   2: 2263.193 ops/ms
Iteration   3: 2201.354 ops/ms
Iteration   4: 2282.906 ops/ms
Iteration   5: 2130.322 ops/ms

# Run progress: 87.48% complete, ETA 00:00:46
# Fork: 2 of 2
# Warmup Iteration   1: 2207.800 ops/ms
# Warmup Iteration   2: 2269.887 ops/ms
# Warmup Iteration   3: 2239.005 ops/ms
Iteration   1: 2001.840 ops/ms
Iteration   2: 2047.698 ops/ms
Iteration   3: 2349.138 ops/ms
Iteration   4: 2362.165 ops/ms
Iteration   5: 2305.982 ops/ms


Result "ltd.newbee.mall.MethodNameTest.m4":
  2220.688 ±(99.9%) 186.910 ops/ms [Average]
  (min, avg, max) = (2001.840, 2220.688, 2362.165), stdev = 123.629
  CI (99.9%): [2033.778, 2407.598] (assumes normal distribution)

直接看最后 Result "ltd.newbee.mall.MethodNameTest.m4": 這里,平均 ops 是每毫秒 2220 次。對比 第一種和第二種方案的 幾十 ops 來說性能提升也很客觀,但是對比第三種方法的上萬級別 ops 還是不足。

四種方案的最終得分對比

Benchmark           Mode  Cnt      Score     Error   Units
MethodNameTest.m1  thrpt   10     17.267 ±   0.184  ops/ms
MethodNameTest.m2  thrpt   10     25.280 ±   1.088  ops/ms
MethodNameTest.m3  thrpt   10  10702.347 ± 672.631  ops/ms
MethodNameTest.m4  thrpt   10   2220.688 ± 186.910  ops/ms
MethodNameTest.m1     ss   10      0.686 ±   0.289   ms/op
MethodNameTest.m2     ss   10      0.339 ±   0.287   ms/op
MethodNameTest.m3     ss   10      0.031 ±   0.011   ms/op
MethodNameTest.m4     ss   10      0.074 ±   0.027   ms/op

根據(jù)最后得分可以看出,四種方案中性能最好的方案是基于匿名內(nèi)部類的 getClass().getEnclosingMethod() 方案,性能第二是的是基于 Java 9 出現(xiàn)的 Stack-Walking API 方案,其他兩種性能過于低下了。

責任編輯:武曉燕 來源: waynblog
相關推薦

2025-02-18 16:27:01

2023-03-20 15:14:39

視覺回歸測試軟件開發(fā)

2024-01-17 13:56:00

Redis節(jié)點映射關系

2023-02-10 11:13:42

網(wǎng)絡功耗無線網(wǎng)絡設備

2010-10-19 17:40:30

SqlServer主鍵

2023-08-30 23:41:16

AI框架項目

2023-08-26 20:08:15

分庫分表Spring

2015-07-23 14:50:28

大數(shù)據(jù)

2009-12-09 11:03:45

安裝Linux

2023-05-30 08:38:25

MySQL數(shù)據(jù)庫日志

2011-08-29 17:13:03

外連接不等值連接等值連接

2015-07-15 10:36:31

2019-08-13 09:00:24

REST API身份認證密鑰

2014-03-17 09:22:43

Linux命令

2022-09-02 14:29:01

JavaScrip數(shù)組屬性

2020-04-07 10:05:34

React開發(fā)工具

2013-07-26 16:38:54

OpenStackHadoop

2021-08-25 12:55:33

Linuxcron

2010-01-12 12:15:25

SOA安全解決方案

2017-02-28 14:28:37

數(shù)據(jù)跨庫分頁架構
點贊
收藏

51CTO技術棧公眾號