2010-07-28 12 views
6

Je veux obtenir un tableau d'octets (Array [Byte]) à partir de quelque part (lire à partir d'un fichier, d'une socket, etc) et ensuite fournir un moyen efficace d'extraire des bits (par exemple fournir une fonction bit entier de l'offset N dans le tableau). Je voudrais ensuite envelopper le tableau d'octets (en le cachant) fournissant des fonctions pour extraire les bits de la matrice (probablement en utilisant des valeurs paresseuses pour chaque bit à retirer).Quel est le moyen le plus efficace de faire des tableaux d'octets immuables dans Scala?

J'imagine avoir une classe enveloppante qui prend un type de tableau d'octets immuable dans le constructeur pour prouver que le contenu du tableau n'est jamais modifié. IndexedSeq [Byte] semblait pertinent, mais je ne pouvais pas savoir comment passer de Array [Byte] à IndexedSeq [Byte].

La partie 2 de la question est si j'ai utilisé IndexedSeq [Byte] le code résultant sera-t-il plus lent? J'ai besoin que le code s'exécute aussi vite que possible, donc je m'en tiendrai à Array [Byte] si le compilateur peut faire un meilleur travail avec.

Je pourrais écrire une classe wrapper autour du tableau, mais cela ralentirait les choses - un niveau supplémentaire d'indirection pour chaque accès aux octets dans le tableau. Les performances sont critiques en raison du nombre d'accès au tableau requis. J'ai besoin de code rapide, mais je voudrais bien faire le code en même temps. Merci!

PS: Je suis un débutant Scala.

Répondre

13

traitement Array[T] comme IndexedSeq[T] pourrait difficilement être plus simple:

Array(1: Byte): IndexedSeq[Byte] // trigger an Implicit View 
wrapByteArray(Array(1: Byte)) // explicitly calling 

Unboxing vous tuer bien avant une couche supplémentaire de indirection.

C:\>scala -Xprint:erasure -e "{val a = Array(1: Byte); val b1: Byte = a(0); val 
b2 = (a: IndexedSeq[Byte])(0)}" 
[[syntax trees at end of erasure]]// Scala source: scalacmd5680604016099242427.s 
cala 

val a: Array[Byte] = scala.Array.apply((1: Byte), scala.this.Predef. 
wrapByteArray(Array[Byte]{})); 
val b1: Byte = a.apply(0); 
val b2: Byte = scala.Byte.unbox((scala.this.Predef.wrapByteArray(a): IndexedSeq).apply(0)); 

Pour éviter cela, la bibliothèque de collections Scala devrait être spécialisé sur le type d'élément, dans le même style que Tuple1 et Tuple2. On me dit que c'est prévu, mais c'est un peu plus compliqué que de simplement taper @specialized partout, donc je ne sais pas combien de temps ça va prendre.

MISE À JOUR

Oui, WrappedArray est mutable, bien que collection.IndexedSeq[Byte] n'a pas les méthodes de muter, de sorte que vous pouvez les clients tout simplement confiance pour ne pas jeter à une interface mutable. La prochaine version de Scalaz comprendra ImmutableArray qui empêche cela.

La boxe vient récupérer un élément de la collection via cette méthode générique:

trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => 
    def apply(idx: Int): A 
} 

Au niveau JVM, cette signature est de type effacée à:

def apply(idx: Int): Object 

Si votre collection contient des primitives , c'est-à-dire sous-types de AnyVal, ils doivent être encadrés dans l'encapsuleur correspondant à renvoyer de cette méthode. Pour certaines applications, il s'agit d'une préoccupation de performance majeure. Des bibliothèques entières ont été écrites en Java pour éviter cela, notamment fastutils.

Annotation directed specialization a été ajouté à Scala 2.8 pour indiquer au compilateur de générer différentes versions d'une classe ou d'une méthode adaptée aux permutations des types primitifs. Cela a déjà été appliqué à quelques endroits dans la bibliothèque standard, par ex. TupleN, ProductN, Function{0, 1, 2}.Si cela était également appliqué à la hiérarchie des collections, ce coût de performance pourrait être allégé.

+0

Désolé, en tant que débutant Scala je ne comprends pas votre exemple. Êtes-vous en train de dire que l'utilisation de Array [Byte] fera beaucoup de déballage? Aussi je n'étais pas sûr de savoir comment déclencher la vue implicite. J'ai ajouté naïvement ": IndexedSeq [Byte]" après l'instanciation de mon tableau mais il s'est plaint de "incompatibilité de type". En outre, wrapByteArray() semble renvoyer un IndexedSeq [Byte] mutable, pas la version immuable. –

11

Si vous voulez travailler avec des séquences à Scala, je vous recommande de choisir l'un de ces:

seqs Immuable:

(seqs liés) Liste, Stream, Queue

(indexé SEQS) Vector

mutables seqs:

(lié seq) ListBuffer

(indexé seq) ArrayBuffer

Le nouveau (2.8) collections Scala ont été difficiles à saisir pour moi, surtout en raison du manque de documentation (correcte), mais aussi à cause du code source (hiérarchies complexes). Pour effacer mon esprit, je pris cette photo pour visualiser la structure de base:

alt text http://www.programmera.net/scala/img/seq_tree.png

Notez également que Array ne fait pas partie de la structure de l'arbre, il est un cas particulier, car il enveloppe le tableau Java (qui est un cas particulier en Java).

+3

Dans Scala 2.8, son 'Array' est pour les tableaux de Java car' String' de Scala est '' 'String' de Java: Un seul et même, pas encapsulé. Il y a des wrappers avec des conversions implicites correspondantes qui permettent d'utiliser des choses comme les HOFs de Scala pour les séquences avec ces types "empruntés", mais les 'Array' (et' String') de base sont les entités Java. –

+0

Merci - mais un commentaire sur la performance de l'approche? C'est-à-dire, si j'utilise IndexedSeq [Byte] dans mon code, sera-t-il aussi rapide que Array [Byte] (byte [] en Java)? Je note qu'une autre réponse met en garde au sujet des frais généraux de déballage - est-ce que ceux-ci vont tuer les performances de Scala pour traiter des tableaux d'octets? –

+1

'Vector' (la seule sous-classe instanciable de' IndexedSeq' autre que les différentes classes 'Range' et' WrappedString') n'est pas spécialisée (pour tout type d'élément) dans Scala 2.8.0, donc vous allez payer une mémoire élevée les frais généraux ainsi que le coût d'un temps d'accès marginal, tous liés à la boxe et au déballage, comme vous le dites. –