performance - librerias - ¿Por qué hay tan pocas cosas especializadas en la biblioteca estándar de Scala?
librerias en lenguaje c y sus funciones (3)
He buscado el uso de @specialized
en el código fuente de la biblioteca estándar de Scala 2.8.1. Parece que solo un puñado de rasgos y clases usan esta anotación: Function0
, Function1
, Function2
, Tuple1
, Tuple2
, Product1
, Product2
, AbstractFunction0
, AbstractFunction1
, AbstractFunction2
.
Ninguna de las clases de colección está @specialized
. Por qué no? ¿Esto generaría demasiadas clases?
Esto significa que el uso de clases de recolección con tipos primitivos es muy ineficiente, ya que habrá una gran cantidad de boxeo y desempaquetado innecesarios.
¿Cuál es la forma más eficiente de tener una lista o secuencia inmutables (con características IndexedSeq
) de Int
, evitando el boxeo y el desempaquetado?
La especialización puede ser costosa ( exponencial ) tanto en tamaño de clases como en tiempo de compilación. No es solo el tamaño como dice la respuesta aceptada.
Abra su scala REPL y escriba esto.
import scala.{specialized => sp}
trait S1[@sp A, @sp B, @sp C, @sp D] { def f(p1:A): Unit }
Lo siento :-). Es como una bomba compiladora.
Ahora, tomemos un rasgo simple
trait Foo[Int]{ }
Lo anterior resultará en dos clases compiladas. Foo, la interfaz pura y Foo $ 1, la implementación de la clase.
Ahora,
trait Foo[@specialized A] { }
Aquí se amplía / reescribe un parámetro de plantilla especializado para 9 tipos primitivos diferentes (void, boolean, byte, char, int, long, short, double, float). Entonces, básicamente terminas con 20 clases en lugar de 2.
Volviendo al rasgo con 5 parámetros de plantilla especializados, las clases se generan para cada combinación de posibles tipos primitivos. es decir, su exponencial en complejidad.
2 * 10 ^ (no de parámetros especializados)
Si está definiendo una clase para un tipo primitivo específico, debe ser más explícito al respecto, como
trait Foo[@specialized(Int) A, @specialized(Int,Double) B] { }
Es comprensible que uno tenga que ser frugal mediante la especialización cuando construya bibliotecas de propósito general.
Here está Paul Phillips despotricando al respecto.
La especialización tiene un alto costo en el tamaño de las clases, por lo que debe agregarse con una consideración cuidadosa. En el caso particular de las colecciones, me imagino que el impacto será enorme.
Aún así, es un esfuerzo continuo: la biblioteca de Scala apenas ha comenzado a especializarse.
Respuesta parcial a mi propia pregunta: puedo envolver un conjunto en un IndexedSeq
como este:
import scala.collection.immutable.IndexedSeq
def arrayToIndexedSeq[@specialized(Int) T](array: Array[T]): IndexedSeq[T] = new IndexedSeq[T] {
def apply(idx: Int): T = array(idx)
def length: Int = array.length
}
(Por supuesto, todavía puede modificar los contenidos si tiene acceso a la matriz subyacente, pero me aseguraré de que la matriz no se pase a otras partes de mi programa).