2012-10-12 59 views
5

The easiest way to convert a Java Collection to a Scala equivalent is using JavaConversions, since Scala 2.8.創建Scala的並行集合。這些隱式defs返回包含Java Collection的包裝器。如何從Java集合

的Scala 2.9引入平行集合,其中在收集操作可並行執行,其結果後收集。這是很容易實現的,現有的集合轉換成平行的一個是簡單的:

myCollection.par 

但有使用「相提並論」上使用JavaConversions Java集合轉換集合的一個問題。正如Parallel Collection Conversions描述,本質上連續集合「逼」到一個新的並行收集通過評估所有的值,並將它們添加到新的並行採集:

其他收藏品,如列表,隊列或流,是固有地是 連續的意思,即必須在 之後訪問另一個元素。通過將這些元素複製到類似的並行集合中,將這些集合轉換爲其並行變體 。例如,一個功能列表被轉換成一個標準的不可變的並行序列,這是一個並行向量。

當原始Java集合打算進行懶惰評估時,會導致問題。例如,如果只返回一個Java Iterable,後來轉換爲Scala Iterable,則不能保證Iterable的內容可以被急切地訪問或不被訪問。 那麼應該如何從Java集合中創建並行集合,而不需要支持評估每個元素的成本呢?這是我試圖避免使用並行集合並行執行它們並希望'採取'提供的前n個結果的成本。

根據Parallel Collection Conversions有一系列的收集類型需要花費不變的時間,但似乎沒有辦法確保這些類型可以由JavaConversions創建(例如,可以創建'Set'但那是一個'HashSet'?)。

+1

請注意,使用JavaConverters而不是JavaConversions作爲後者會更好,在那裏您可以執行類似.asScala.toList.par的操作。 –

回答

4

首先,通過JavaConversion從Java集合獲得的每個集合都不是默認的可並行化的Scala集合 - 這意味着它將始終被重新評估爲其相應的並行集合實現。原因在於並行執行至少依賴於Splitters的概念 - 它必須被拆分成更小的子集,然後不同的處理器才能進行工作。

我不知道Java集合是如何在數據結構意義上看起來的,但是如果它是一棵樹狀的東西或其下面的元素被懶惰評估的數組,那麼很可能您可以輕鬆實現Splitter

如果您不想急於將force作爲實現Java集合API的惰性集合,那麼您唯一的選擇是針對該特定惰性Java集合的implement a new type of a parallel collection。在這個新的實現中,你必須提供分割迭代器的手段(即,一個Splitter)。

一旦你實現了這個知道如何拆分你的數據結構的新並行集合,你應該爲你的特定的Java集合創建一個定製的Scala包裝器(在這一點上它只是一些額外的樣板,看看它是如何完成的在JavaConversions)並覆蓋它的par以返回您的特定平行集合。

您甚至可以對索引序列進行一般操作。假設您的Java集合是一個使用特別有效的get方法的序列(用Java編寫,List),您可以實現Splitter作爲迭代器,它在從0size - 1的初始範圍內調用get,並通過細分此範圍來分割。

如果這樣做,標準庫的補丁總是受歡迎的。

1

並行需要隨機訪問和java.lang.Iterable不提供它。這是一個根本性的不匹配,沒有任何轉換可以讓您輕鬆過去。

要使用非編程比喻,你不能在同一時間從澳大利亞發從新加坡一個人到英國,另一個是新加坡獲得來自澳大利亞到英國的人。

或者編程,如果你正在處理數據的實時流,你不能在同一時間從五分鐘前的數據從現在開始處理數據,而無需增加延遲parallelise它。

您需要的,而不是可迭代的東西,至少提供了一些隨機訪問,就像java.util.List.listIterator(INT)。

+0

我想我假設每個調用來檢索下一個元素(即Iterable.iterator()。next())在線程中運行。 –