如何从Java集合创建Scala并行集合

时间:2012-10-12 12:39:41

标签: java scala collections parallel-collections

The easiest way to convert a Java Collection to a Scala equivalent is using JavaConversions, since Scala 2.8.。这些隐式defs返回包含的Java Collection的包装器。

Scala 2.9引入了并行集合,可以并行执行集合上的操作,并在以后收集结果。这很容易实现,将现有集合转换为并行集合非常简单:

myCollection.par

但是在使用JavaConversions从Java集合转换的集合上使用'par'时出现问题。如Parallel Collection Conversions中所述,通过评估所有值并将它们添加到新的并行集合中,本质上将顺序集合“强制”为新的并行集合:

  

其他集合,例如列表,队列或流,本身就是其中之一   顺序,因为元素必须在一个之后被访问   另一个。这些集合将转换为其并行变体   通过将元素复制到类似的并行集合中。对于   例如,功能列表转换为标准不可变   并行序列,是一个平行向量。

当原始Java集合要进行延迟评估时,这会导致问题。例如,如果仅返回Java Iterable,稍后将其转换为Scala Iterable,则无法保证Iterable的内容是否会被急切访问。 那么如何在不花费评估每个元素的成本的情况下从Java集合中创建并行集合呢?我试图通过使用并行集合来并行执行它们来避免这种成本,并希望'取'提供的前n个结果。

根据Parallel Collection Conversions,有一系列的收集类型花费了不变的时间,但似乎没有办法确保JavaConversions可以创建这些类型(例如'Set'可以被创建,但是'HashSet'?)。

2 个答案:

答案 0 :(得分:4)

首先,从Java集合中通过JavaConversion获得的每个集合都不是默认的可并行化Scala集合 - 这意味着它将始终重新评估到其对应的并行集合实现中。这样做的原因是并行执行至少依赖于Splitters的概念 - 它必须可以拆分成更小的子集,然后不同的处理器可以使用它们。

我不知道你的Java集合在数据结构意义上看起来如何,但如果它是一个树状的东西或下面的数组,其元素被懒惰地评估,很可能你可以很容易地实现{{1} }。

如果您不想急切地Splitter实现Java集合API的惰性集合,那么对于该特定的懒惰Java集合,您唯一的选择是implement a new type of a parallel collection。在这个新实现中,您必须提供拆分迭代器的方法(即force)。

一旦实现了这个知道如何拆分数据结构的新并行集合,就应该为特定的Java集合创建一个自定义Scala包装器(此时它只是一些额外的样板,看看它是如何完成的Splitter)并覆盖其JavaConversions以返回您的特定并行集合。

您甚至可以为索引序列执行此操作。鉴于您的Java集合是一个具有特别高效的par方法的序列(在Java中,List),您可以将get实现为在其中调用Splitter的迭代器初始范围从get0,并通过细分此范围进行拆分。

如果这样做,欢迎使用标准库的补丁。

答案 1 :(得分:1)

并行需要随机访问,而java.lang.Iterable并不提供它。这是一个根本的不匹配,任何数量的转换都不会轻易让你过去。

要使用非编程类比,您不能将一个人从新加坡送到英格兰,另一个人从澳大利亚同时送到新加坡。

或者在编程中,如果您正在处理实时数据流,则无法通过现在处理数据与五分钟前的数据同时处理数据,而不会增加延迟。

你需要一些能提供至少一些随机访问的东西,比如java.util.List.listIterator(Int)而不是Iterable。