2010-07-28 28 views
6

我想從某處(從文件,從套接字等讀取)獲取一個字節數組(數組[字節]),然後提供一個有效的方法來從中拉出比特(例如提供一個函數,數組中的偏移量N中的一位整數)。然後,我想包裝字節數組(隱藏它)提供的功能,從數組中拉出位(可能使用lazy val來提取每個位)。在Scala中執行不可變字節數組的最有效方法是什麼?

我會想象有一個包裝類,它在構造函數中採用不可變的字節數組類型來證明數組內容永遠不會被修改。 IndexedSeq [Byte]似乎是相關的,但我不知道如何從Array [Byte]到IndexedSeq [Byte]。

問題的第2部分是如果我使用IndexedSeq [Byte],結果代碼是否會變慢?我需要儘可能快地執行代碼,所以如果編譯器可以更好地處理它,那麼會堅持使用Array [Byte]。

我可以在數組周圍編寫一個包裝類,但這會減慢速度 - 每次訪問數組中的字節時會有一個額外的間接級別。由於需要進行數組訪問,因此性能至關重要。我需要快速代碼,但想要在同一時間很好地完成代碼。謝謝!

PS:我是斯卡拉新手。

回答

13

治療Array[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集合庫應專門元素類型,在相同的風格Tuple1Tuple2。我被告知這是計劃中的事情,但這比簡單地將@specialized拍到任何地方都要多一點,所以我不知道需要多長時間。

UPDATE

是,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

Annotation directed specialization被添加到Scala 2.8中,以指示編譯器生成針對原始類型的排列而定製的各種版本的類或方法。這已經被應用到標準庫中的一些地方,例如, TupleNProductNFunction{0, 1, 2}。如果這也適用於收藏層次結構,則可以緩解該性能成本。

+0

對不起,作爲一個斯卡拉新手我不明白你的例子。你是說使用Array [Byte]會做很多拆箱?另外我不確定如何觸發隱式視圖。我天真地添加了「:IndexedSeq [Byte]」之後我的數組實例化,但它抱怨「類型不匹配」。此外,wrapByteArray()似乎返回一個可變的IndexedSeq [Byte],而不是不可變的版本。 – 2010-07-28 15:00:41

11

如果你想在斯卡拉序列工作,我建議你選擇其中之一:

永恆seqs:

(聯seqs)名單,流,隊列

(索引seqs)矢量

易變seqs:

(聯SEQ)ListBuffer

(索引序列)ArrayBuffer

新(2.8)Scala集合已經很難把握對我來說,主要是由於(正確的)文檔的短缺也是因爲源代碼(複雜的層次結構)。要清除我的腦海裏我做了這個PIC以可視化的基本結構:

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

另外,請注意Array不是樹形結構的一部分,它是一個特例,因爲它包裝了Java數組(在Java中是特例)。

+3

在Scala 2.8中,它的'Array'是Java的數組,因爲Scala的'String'是Java的'String':一個也是一樣的,沒有被包裝。有相應的隱式轉換的包裝,允許像Scala的HOFs這樣的序列用於這些「借用」類型,但基本的'Array'(和'String')是Java實體。 – 2010-07-28 14:00:48

+0

謝謝 - 但對這種方法的性能有何評論?也就是說,如果我在我的代碼中使用IndexedSeq [Byte],它會和Array [Byte](Java中的byte [])一樣快嗎?我注意到另一個響應警告拆箱開銷 - 這些是否會殺死處理字節數組的Scala性能? – 2010-07-28 14:53:56

+1

'Vector'(除了各種'Range'類和'WrappedString'外,'IndexedSeq'唯一可實例化的子類)在Scala 2.8.0中沒有專門化(對於任何元素類型),因此您要支付高內存開銷以及邊際訪問時間成本,全部歸因於拳擊和拆箱,就像你說的那樣。 – 2010-07-28 20:01:39

相關問題