2014-07-17 95 views
2

如果我有我通過模式匹配解析到原始的如Int一個泛型參數,是自動裝箱比使用一個定製的包裝類型便宜?例如。自動裝箱操作比自定義包裝類型執行得更好嗎?

def test[A](x: A): Int = x match { 
    case i: Int => i 
    case _ => -1 
} 

case class NumChannels(value: Int) 

def test[A](x: A): Int = x match { 
    case n: NumChannels => n.value 
    case _ => -1 
} 

做的第一方式提供任何性能優勢?如果方法使用的是Any,則此情況相同:

def test(x: Any): Int = ... 

+1

什麼是你的分析結果,以及如何爲他們令人驚訝的? – rightfold

+0

我沒有分析。我試圖做出決定哪種API來解決。 –

+0

爲什麼不根據結果進行簡介並做出決定,而不是依賴投機? – rightfold

回答

2

如果你看的javap輸出(僅其不同的部分):使用

10: invokestatic #17     // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I 
13: istore_3  
14: iload_3  
  • 版本:

    • 版本使用IntNumChannels
    10: checkcast  #12     // class app/benchmark/scala/benchmark3b/NumChannels 
        13: astore_3  
        14: aload_3  
        15: invokevirtual #16     // Method app/benchmark/scala/benchmark3b/NumChannels.value:()I 
    

    人們可以假設,第一個版本應該會更快。使用Any的第三個版本的結果與第一個版本相同。

    然而,使用江鈴控股微基準測試顯示沒有實質性差別:

    Benchmark        Mode Samples   Mean Mean error Units 
    a.b.s.benchmark3a.Benchmark3a.run thrpt   5  42,352  0,480 ops/ms 
    a.b.s.benchmark3b.Benchmark3b.run thrpt   5  42,793  1,439 ops/ms 
    

    使用Oracle JDK 1.8,斯卡拉2.9.3,Linux 32位。


    月1日基準:

    @State(Scope.Benchmark) 
    object BenchmarkState { 
        final val n = 10000 
    
        val input = 
        Array.range(0, n).map { 
         n => 
         if (n % 2 == 0) { 
          n 
         } else { 
          "" + n 
         } 
        } 
    } 
    
    class Benchmark3a { 
        def test[A](x: A): Int = x match { 
        case i: Int => i 
        case _ => -1 
        } 
    
        @GenerateMicroBenchmark 
        def run() = { 
        var sum = 0 
        var i = 0 
        while (i < BenchmarkState.n) { 
         sum += test(BenchmarkState.input(i)) 
         i +=1 
        } 
        sum 
        } 
    } 
    

    第二基準

    case class NumChannels(value: Int) 
    
    @State(Scope.Benchmark) 
    object BenchmarkState { 
        final val n = 10000 
    
        val input = 
        Array.range(0, n).map { 
         n => 
         if (n % 2 == 0) { 
          NumChannels(n) 
         } else { 
          "" + n 
         } 
        } 
    } 
    
    class Benchmark3b { 
        def test[A](x: A): Int = x match { 
        case n: NumChannels => n.value 
        case _ => -1 
        } 
    
        @GenerateMicroBenchmark 
        def run() = { 
        var sum = 0 
        var i = 0 
        while (i < BenchmarkState.n) { 
         sum += test(BenchmarkState.input(i)) 
         i +=1 
        } 
        sum 
        } 
    } 
    

    在以前的版本我用Seq和方法mapsum,和博th版本的性能同樣如此,但它們只能達到4 ops/ms左右。

    即使使用Arraywhile不顯露真正的區別。

    所以,我要說,這(隔離)API設計的決定不會影響性能。


    資源

+0

感謝您的廣泛測試;你在這裏使用了哪個基準框架? –

+0

JMH - 在回答中間隱藏得很好:-)。我已經添加了一個鏈接。據我所知,sbt-jmh插件目前只包含基於Scala的基準測試(對於Scala/Java比較,我使用的是基於maven的測試) – Beryllium