13

私は現在、コードのパフォーマンスに関連する部分として、型クラスのパターンを多用しています。私は少なくとも2つの潜在的な非効率の原因を突き止めました。

  1. 暗黙的なパラメータは、メッセージ呼び出しに沿って渡されます。これが本当に起こるかどうかはわかりません。たぶん、scalacは、それらが使用されている場所に暗黙のパラメーターを挿入し、メソッドシグネチャからそれらを削除することができます。暗黙的なパラメータを手動で挿入する場合、実行時にのみ解決される可能性があるため、これはおそらく不可能です。暗黙のパラメータの受け渡しに関してどのような最適化が適用されますか?

  2. 型クラスインスタンスがdef(とは対照的にval)によって提供される場合、「型クラス化されたメソッド」を呼び出すたびにオブジェクトを再作成する必要があります。この問題は、オブジェクトの作成を最適化する可能性のあるJVMによって解決される可能性があります。この問題は、これらのオブジェクトを再利用することでscalacによって解決される可能性もあります。暗黙のパラメータオブジェクトの作成に関してどのような最適化が適用されますか?

そしてもちろん、型クラスパターンを適用するときに非効率の追加の原因があるかもしれません。それらについて教えてください。

4

1 に答える 1

8

あなたが本当に超高性能コードを書くことに関心があるなら(そしてあなたはそう思うかもしれませんが、これについては非常に間違っているかもしれません)、型クラスは以下の理由でいくらかの苦痛を引き起こすでしょう:

  • 多くの追加の仮想メソッド呼び出し
  • プリミティブのボクシングの可能性(たとえば、モノイドなどにscalazの型クラスを使用する場合)
  • def関数をパラメータ化できないために必要なオブジェクトの作成
  • 「pimped」メソッドにアクセスするためのオブジェクトの作成

実行時に、JVMは誤った作成の一部を最適化する可能性があります(たとえば、MA単に呼び出すための作成<*>)が、scalacあまり役に立ちません。型クラスを使用するコードをコンパイル-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();
    ()
   }
 }

}

ここで大量のオブジェクトが作成されていることがわかります

于 2012-02-17T12:14:10.483 に答える