在Scala中使用类型类模式会对性能产生什么影响



我目前正在大量使用中的类型类模式来作为代码中与性能相关的部分。我发现了至少两个潜在的低效来源。

  1. 隐式参数随消息调用一起传递。我不知道这是否真的发生了。也许scalac可以简单地将隐式参数插入到使用它们的位置,并将它们从方法签名中删除。在手动插入隐式参数的情况下,这可能是不可能的,因为它们可能只在运行时解析在传递隐式参数方面应用了哪些优化

  2. 如果类型类实例是由def提供的(与val相反),则必须在每次调用"类型分类方法"时重新创建对象。JVM可能会解决这个问题,它可能会优化对象的创建。scalac也可以通过重用这些对象来解决这个问题对于隐式参数对象的创建,应用了哪些优化

当然,在应用类型类模式时,可能还有其他低效的来源。请告诉我他们的情况。

如果你真的关心编写超高性能代码(你可能认为你这样做了,但对此非常错误),那么类型类会引起一些痛苦,原因如下:

  • 许多额外的虚拟方法调用
  • 基元的可能装箱(例如,如果对monoid等使用scalaz的类型类)
  • 通过def创建对象是必要的,因为函数不能参数化
  • 创建对象以访问"皮条"方法

在运行时,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();
    ()
   }
 }

}

您可以看到这里正在进行大量的对象创建。

相关内容

  • 没有找到相关文章

最新更新