2012-02-17 66 views
13

我目前正在廣泛使用類型模式來成爲我的代碼的性能相關部分。我發現至少有兩個潛在的低效率來源。在Scala中使用類型模式會對性能產生什麼影響

  1. 隱式參數傳遞給消息調用。我不知道這是否真的發生。也許scalac可以簡單地在使用它們的地方插入隱式參數並將它們從方法簽名中移除。在手動插入隱式參數的情況下,這可能不可行,因爲它們可能僅在運行時被解析。 對於傳遞隱式參數適用什麼優化

  2. 如果類型類實例由def(與val相反)提供,則必須在每次調用「類型分類方法」時重新創建對象。 JVM可能會優化此問題,這可能會優化對象創建。通過重用這些對象,scalac也可能會解決這個問題。 對隱式參數對象的創建適用什麼優化?

當然並應用型類模式時,有可能是低效率的其他來源。請告訴我他們。

回答

8

如果你真的在乎編寫超高性能的代碼(你可以認爲你做,但要非常錯誤這個),那麼類型類會造成一定的痛苦,原因如下:

  • 很多額外的虛擬方法調用
  • 元的可能的拳擊(例如,如果使用scalaz對類羣等類型類)
  • 對象創建通過def這是必要的,因爲功能不能對meterized
  • 對象創建訪問「拉皮條」方法

在運行時,JVM可以優化一些錯誤的創作遠(例如創建一個MA只需致電<*>),但scalac並沒有太大的幫助。你可以通過編譯一些使用typeclass並使用-Xprint:icode作爲參數的代碼來看到這一點。

下面是一個例子:

import scalaz._; import Scalaz._ 
object TC { 
    def main(args: Array[String]) { 
    println((args(0).parseInt.liftFailNel |@| args(1).parseInt.liftFailNel)(_ |+| _)) 
    } 
} 

而這裏的ICODE:

final object TC extends java.lang.Object with ScalaObject { 
    def main(args: Array[java.lang.String]): Unit = scala.this.Predef.println(scalaz.this.Scalaz.ValidationMA(scalaz.this.Scalaz.StringTo(args.apply(0)).parseInt().liftFailNel()).|@|(scalaz.this.Scalaz.StringTo(args.apply(1)).parseInt().liftFailNel()).apply({ 
    (new anonymous class TC$$anonfun$main$1(): Function2) 
}, scalaz.this.Functor.ValidationFunctor(), scalaz.this.Apply.ValidationApply(scalaz.this.Semigroup.NonEmptyListSemigroup()))); 
def this(): object TC = { 
    TC.super.this(); 
() 
} 
}; 
@SerialVersionUID(0) final <synthetic> class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2 extends scala.runtime.AbstractFunction0 with Serializable { 
    final def apply(): Int = TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.this.v1$1; 
    final <bridge> def apply(): java.lang.Object = scala.Int.box(TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.this.apply()); 
    <synthetic> <paramaccessor> private[this] val v1$1: Int = _; 
    def this($outer: anonymous class TC$$anonfun$main$1, v1$1: Int): anonymous class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2 = { 
    TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.this.v1$1 = v1$1; 
    TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.super.this(); 
    () 
    } 
}; 
@SerialVersionUID(0) final <synthetic> class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1 extends scala.runtime.AbstractFunction0$mcI$sp with Serializable { 
    final def apply(): Int = TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.apply$mcI$sp(); 
    <specialized> def apply$mcI$sp(): Int = TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.v2$1; 
    final <bridge> def apply(): java.lang.Object = scala.Int.box(TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.apply()); 
    <synthetic> <paramaccessor> private[this] val v2$1: Int = _; 
    def this($outer: anonymous class TC$$anonfun$main$1, v2$1: Int): anonymous class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1 = { 
    TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.v2$1 = v2$1; 
    TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.super.this(); 
() 
    } 
}; 
@SerialVersionUID(0) final <synthetic> class TC$$anonfun$main$1 extends scala.runtime.AbstractFunction2$mcIII$sp with Serializable { 
    final def apply(x$1: Int, x$2: Int): Int = TC$$anonfun$main$1.this.apply$mcIII$sp(x$1, x$2); 
    <specialized> def apply$mcIII$sp(v1$1: Int, v2$1: Int): Int = scala.Int.unbox(scalaz.this.Scalaz.mkIdentity({ 
(new anonymous class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2(TC$$anonfun$main$1.this, v1$1): Function0) 
}).|+|({ 
    (new anonymous class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1(TC$$anonfun$main$1.this, v2$1): Function0) 
}, scalaz.this.Semigroup.IntSemigroup())); 
final <bridge> def apply(v1: java.lang.Object, v2: java.lang.Object): java.lang.Object = scala.Int.box(TC$$anonfun$main$1.this.apply(scala.Int.unbox(v1), scala.Int.unbox(v2))); 
    def this(): anonymous class TC$$anonfun$main$1 = { 
    TC$$anonfun$main$1.super.this(); 
    () 
    } 
} 

}

你可以看到有回事

+0

所以一個對象創建的數量巨大我從你的答案中讀到的建議可能是用自己的版本替換我正在使用的'scalaz.Monoid' cialization?雖然專業化似乎是非常麻煩的...即使'數字'看起來並沒有專門化。 – ziggystar 2012-02-17 12:39:15

+0

我會避開專精tbh。如果我在你的鞋子裏,我會非常非常肯定地說,我確實需要從代碼中擠出最後一滴表現。是什麼讓你確定你做的?如果事物必須接近金屬,那麼我會說你必須回到可變集合,命令式代碼和while循環。真的沒有其他答案 – 2012-02-17 12:42:54

+0

它並不一定要儘可能快。但我不想承受拳擊的表現影響。我目前正在使用原始數組(沒有改變它們)。關於這個問題,可以保持代碼非常通用,以適用於大問題空間(我甚至使用代數環作爲抽象)。目前我不想在表演之間做出決定(比如拳擊10次命中)和抽象;這不是一個容易的選擇,我想知道我能夠走多遠。 – ziggystar 2012-02-17 12:51:32

相關問題