如果你真的在乎編寫超高性能的代碼(你可以認爲你做,但要非常錯誤這個),那麼類型類會造成一定的痛苦,原因如下:
- 很多額外的虛擬方法調用
- 元的可能的拳擊(例如,如果使用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();
()
}
}
}
你可以看到有回事
所以一個對象創建的數量巨大我從你的答案中讀到的建議可能是用自己的版本替換我正在使用的'scalaz.Monoid' cialization?雖然專業化似乎是非常麻煩的...即使'數字'看起來並沒有專門化。 – ziggystar 2012-02-17 12:39:15
我會避開專精tbh。如果我在你的鞋子裏,我會非常非常肯定地說,我確實需要從代碼中擠出最後一滴表現。是什麼讓你確定你做的?如果事物必須接近金屬,那麼我會說你必須回到可變集合,命令式代碼和while循環。真的沒有其他答案 – 2012-02-17 12:42:54
它並不一定要儘可能快。但我不想承受拳擊的表現影響。我目前正在使用原始數組(沒有改變它們)。關於這個問題,可以保持代碼非常通用,以適用於大問題空間(我甚至使用代數環作爲抽象)。目前我不想在表演之間做出決定(比如拳擊10次命中)和抽象;這不是一個容易的選擇,我想知道我能夠走多遠。 – ziggystar 2012-02-17 12:51:32