Pregunta

Actualmente estoy haciendo un uso extenso del patrón de clase tipo para ser partes relevantes para el rendimiento de mi código. Hice al menos dos posibles fuentes de ineficiencia.

  1. Los parámetros implícitos se transmiten llamadas de mensajes. No sé si esto realmente sucede. Tal vez Scalac simplemente pueda insertar los parámetros implícitos donde se usan y eliminarlos de la firma del método. Probablemente esto no sea posible en los casos en que inserte los parámetros implícitos manualmente, ya que podrían resolverse solo en tiempo de ejecución. ¿Qué optimizaciones se aplican con respecto a los parámetros implícitos de aprobación??

  2. Si la instancia de clase de tipo es proporcionada por un def (contrario a un val), el objeto debe recrearse en cada invocación de un "método de tipo clasificado". Este problema puede ser abordado por el JVM, que podría optimizar la creación de objetos. Este problema también puede ser abordado por Scalac al reutilizar estos objetos. ¿Qué optimizaciones se aplican con respecto a la creación de objetos de parámetros implícitos?

Y, por supuesto, puede haber fuentes adicionales de ineficiencia al aplicar el patrón de clase de tipo. Por favor, cuéntame sobre ellos.

¿Fue útil?

Solución

Si realmente te importa escribir código de ultra alto rendimiento (y puede pensar tú lo haces pero sé muy mal Sobre esto) Entonces los typeclasses causarán algo de dolor por las siguientes razones:

  • Muchas llamadas de método virtual adicional
  • Probablemente boxeo de primitivas (por ejemplo, si se usa typeclasses de Scalaz para monoides, etc.)
  • Creaciones de objetos a través de def que son necesarios porque las funciones no se pueden parametrizar
  • Creaciones de objetos para acceder a los métodos "Pimped"

En tiempo de ejecución, el JVM puede optimizar algunas de las creaciones erróneas de distancia (por ejemplo, la creación de un MA Simplemente para llamar <*>), pero scalac no hace mucho para ayudar. Puede ver esto trivialmente compilando algún código que usa typecLasses y usando -Xprint:icode como argumento.

Aquí hay un ejemplo:

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

Y aquí está el 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();
    ()
   }
 }

}

Puedes ver que hay una gran cantidad de creación de objetos aquí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top