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'?)。
答案 0 :(得分:4)
首先,从Java集合中通过JavaConversion
获得的每个集合都不是默认的可并行化Scala集合 - 这意味着它将始终重新评估到其对应的并行集合实现中。这样做的原因是并行执行至少依赖于Splitter
s的概念 - 它必须可以拆分成更小的子集,然后不同的处理器可以使用它们。
我不知道你的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
的迭代器初始范围从get
到0
,并通过细分此范围进行拆分。
如果这样做,欢迎使用标准库的补丁。
答案 1 :(得分:1)
并行需要随机访问,而java.lang.Iterable并不提供它。这是一个根本的不匹配,任何数量的转换都不会轻易让你过去。
要使用非编程类比,您不能将一个人从新加坡送到英格兰,另一个人从澳大利亚同时送到新加坡。
或者在编程中,如果您正在处理实时数据流,则无法通过现在处理数据与五分钟前的数据同时处理数据,而不会增加延迟。
你需要一些能提供至少一些随机访问的东西,比如java.util.List.listIterator(Int)而不是Iterable。