Что самый эффективный путь состоит в том, чтобы сделать неизменные массивы байтов в Scala?

Я хочу получить массив байтов (Массив [Байт]) от где-нибудь (чтение из файла, из сокета, и т.д.) и затем обеспечить эффективный способ вытащить биты из него (например, обеспечить функцию для извлечения 32-разрядного целого числа из смещения N в массиве). Я затем хотел бы перенести массив байтов (скрывающий его) обеспечение функций для получения по запросу битов из массива (вероятно, использующий ленивый val для каждого бита, чтобы выйти).

Я предположил бы иметь переносящийся класс, который берет неизменный тип массива байтов в конструкторе, чтобы доказать, что содержание массива никогда не изменяется. IndexedSeq [Байт] казался релевантным, но я не мог разработать, как пойти от Массива [Байт] в IndexedSeq [Байт].

Часть 2 вопроса - то, если я использовал IndexedSeq [Байт], результант кодирует быть немного медленнее? Мне нужен код для выполнения максимально быстро, так придерживался бы Массива [Байт], если компилятор мог бы сделать лучшее задание с ним.

Я мог записать класс обертки вокруг массива, но это замедлит вещи - один дополнительный уровень абстракции для каждого доступа к байтам в массиве. Производительность очень важна из-за количества доступов к массиву, которые будут требоваться. Я должен быстро кодировать, но хотел бы сделать код приятно одновременно.Спасибо!

PS: Я - новичок Scala.

6
задан Alan Kent 28 July 2010 в 06:32
поделиться

2 ответа

Обработка массива [T] как IndexedSeq [T] вряд ли может быть проще:

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

Распаковка убьет вас задолго до того, как появится дополнительный слой косвенного обращения.

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

Чтобы избежать этого, библиотека коллекций Scala должна быть специализирована на типе элемента в том же стиле, что и Tuple1 и Tuple2 . Мне сказали, что это запланировано, но это немного сложнее, чем просто шлепать @specialized повсюду, поэтому я не знаю, сколько времени это займет.

ОБНОВЛЕНИЕ

Да, WrappedArray является изменяемым, хотя collection.IndexedSeq [Byte] не имеет методов для изменения, поэтому вы можете просто доверять клиентам, которые не будут приводить к изменяемый интерфейс. Следующий выпуск Scalaz будет включать ImmutableArray , который предотвращает это.

Упаковка осуществляется путем извлечения элемента из коллекции с помощью этого универсального метода:

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

На уровне JVM эта подпись стирается по типу до:

  def apply(idx: Int): Object

Если ваша коллекция содержит примитивы, то есть подтипы AnyVal , они должны быть помещены в соответствующую оболочку для возврата из этого метода. Для некоторых приложений это серьезная проблема с производительностью.Чтобы избежать этого, на Java были написаны целые библиотеки, особенно fastutils .

Специализация, направленная на аннотации , была добавлена ​​в Scala 2.8, чтобы инструктировать компилятор генерировать различные версии класса или метода, адаптированные к перестановкам примитивных типов. Это уже было применено к нескольким местам в стандартной библиотеке, например. TupleN , ProductN , Функция {0, 1, 2} . Если бы это также было применено к иерархии коллекций, эти затраты на производительность можно было бы снизить.

15
ответ дан 8 December 2019 в 04:27
поделиться

Если вы хотите работать с последовательностями в Scala, я рекомендую вам выбрать один из следующих:

Неизменяемые последовательности:

(связанные последовательности) Список, поток, очередь

(индексированные последовательности) Вектор

Mutable seqs:

(связанный seq) ListBuffer

(indexed seq) ArrayBuffer

Новые коллекции Scala (2.8) мне было трудно понять, в первую очередь из-за нехватки (правильной) документации, а также из-за исходный код (сложные иерархии). Чтобы очистить сознание, я сделал этот рисунок, чтобы визуализировать базовую структуру:

alt text
(источник: programmera.net )

Также обратите внимание, что Массив не является частью дерева структура, это особый случай, поскольку она обертывает массив Java (что является особым случаем в Java).

10
ответ дан 8 December 2019 в 04:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: