Каково влияние эффективности использования шаблона класса типа в Scala

StackOverflow https://stackoverflow.com/questions/9327465

Вопрос

В настоящее время я широко использую типовой шаблон класса, чтобы быть релевантными от производительности части моего кода. Я разобрался как минимум два потенциальных источника неэффективности.

  1. Неявные параметры передаются вдоль звонков сообщений. Я не знаю, действительно ли это происходит. Возможно, Scalac может просто вставить неявные параметры, в которых они используются, и удалить их из подписи метода. Это, вероятно, невозможно в тех случаях, когда вы вставляете неявные параметры вручную, поскольку они могут быть разрешены только во время выполнения. Какие оптимизации применяются в отношении прохождения неявных параметров?

  2. Если экземпляр класса типа предоставлен def (вопреки val), объект должен быть воссоздан на каждом вызове «метода классического типа». Эта проблема может быть подана JVM, которая может оптимизировать создание объектов. Эта проблема также может быть подана Scalac, повторно используя эти объекты. Какие оптимизации применяются в отношении создания неявных объектов параметров?

И, конечно, могут быть дополнительные источники неэффективности при применении схемы класса типа. Расскажите, пожалуйста, о них.

Это было полезно?

Решение

Если вы искренне заботитесь о написании кода с ультра-высокой эффективностью (и вы можете считать Вы делаете, но будьте очень неправильно об этом) тогда Typeclasses вызовут некоторую боль по следующим причинам:

  • Много дополнительных вызовов виртуальных методов
  • Вероятно, бокс с примитивами (например, если используют типосессы Scalaz для моноидов и т. Д.)
  • Объектные творения через def которые необходимы, потому что функции не могут быть параметризованы
  • Объектные творения, чтобы получить доступ к методам "ограбленных"

Во время выполнения JVM может оптимизировать некоторые из ошибочных творений (например, создание MA Просто позвонить <*>), но scalac не делает много, чтобы помочь. Вы можете увидеть это тривиально, составив какой -то код, который использует TypeClasses и используя -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();
    ()
   }
 }

}

Вы можете видеть, что здесь происходит огромное количество объектов

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top