Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

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

  • Много дополнительных вызовов виртуальных методов
  • Вероятный бокс примитивов (например, при использовании сказусов для моноидов и т.д.)
  • Создание объектов с помощью 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)(_ |+| _))
  }
}

А вот икода:

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();
    ()
   }
 }

}

Здесь вы видите огромное количество создания объектов.