Frage

Ich verwende derzeit das Typ-Klassenmuster in leistungsrelevante Teile meines Codes. Ich habe mindestens zwei potenzielle Quellen der Ineffizienz erstellt.

  1. Die impliziten Parameter werden mit Nachrichtenaufrufen weitergegeben. Ich weiß nicht, ob das wirklich passiert. Vielleicht kann Scalac einfach die impliziten Parameter einfügen, in denen sie verwendet werden, und sie aus der Methodensignatur entfernen. Dies ist wahrscheinlich nicht möglich, wenn Sie die impliziten Parameter manuell einfügen, da sie möglicherweise nur zur Laufzeit aufgelöst werden. Welche Optimierungen in Bezug auf die Übergabe implizite Parameter gelten?

  2. Wenn die Typ -Klasseninstanz von a bereitgestellt wird def (entgegen a val), das Objekt muss bei jeder Aufruf einer "Art klassifizierten Methode" nachgebildet werden. Dieses Problem kann durch das JVM eingelöst werden, was die Erstellung von Objekten beseitigen kann. Dieses Problem könnte auch von Scalac durch Wiederverwendung dieser Objekte eingehalten werden. Welche Optimierungen gelten in Bezug auf die Erstellung impliziter Parameterobjekte?

Und natürlich gibt es möglicherweise zusätzliche Quellen der Ineffizienz bei der Anwendung des Typs Klassenmuster. Bitte erzählen Sie mir von ihnen.

War es hilfreich?

Lösung

Wenn Sie sich wirklich darum kümmern, ultrahoch-Leistung-Code zu schreiben (und Sie können denken du tust aber sehr falsch darüber) dann verursachen Typenklassen aus folgenden Gründen einige Schmerzen:

  • Viele zusätzliche virtuelle Methodenaufrufe
  • Wahrscheinliches Boxen von Primitiven (z. B. wenn Scalaz 'Typklassen für Monoide usw. verwendet)
  • Objektkreationen über def die notwendig sind, weil Funktionen nicht parametrisiert werden können
  • Objektkreationen, um auf die "Pimped" -Methoden zuzugreifen

Zur Laufzeit kann der JVM einige der fehlerhaften Kreationen optimieren (z. B. die Erstellung eines MA Einfach anrufen <*>), aber scalac tut nicht viel, um zu helfen. Sie können dies trivial sehen, indem Sie einen Code zusammenstellen, der Typenklassen verwendet und verwendet -Xprint:icode als Argument.

Hier ist ein Beispiel:

import scalaz._; import Scalaz._
object TC {
  def main(args: Array[String]) {
    println((args(0).parseInt.liftFailNel |@| args(1).parseInt.liftFailNel)(_ |+| _))
  }
}

Und hier ist die 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();
    ()
   }
 }

}

Sie können sehen, dass hier eine große Menge an Objekterstellung stattfindet

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top