5

从 Scala 2.8 开始,将 Java Collection 转换为 Scala 等价物的最简单方法是使用 JavaConversions。. 这些隐式定义返回包含的 Java 集合的包装器。

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'?)。

4

2 回答 2

4

首先,通过JavaConversions 从 Java 集合中获得的每个集合都不是默认的可并行化 Scala 集合——这意味着它总是会被重新评估为相应的并行集合实现。这样做的原因是并行执行至少依赖于Splitters的概念——它必须被拆分成更小的子集,然后不同的处理器可以处理这些子集。

我不知道你的 Java 集合在数据结构的意义上是怎样的,但如果它是一个树状的东西或一个数组,其元素被懒惰地评估,你很可能可以轻松地实现一个Splitter.

如果您不想急切地force实现一个实现 Java 集合 API 的惰性集合,那么您唯一的选择是为该特定的惰性 Java 集合实现一种新类型的并行集合。在这个新实现中,您必须提供拆分迭代器的方法(即 a Splitter)。

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

您甚至可以对索引序列一般地执行此操作。鉴于您的 Java 集合是具有List特别有效方法的序列(在Java 中为a ) ,get您可以Splitterget0size - 1

如果你这样做了,标准库的补丁总是受欢迎的。

于 2012-10-12T13:07:29.793 回答
1

Parallel 需要随机访问,而 java.lang.Iterable 不提供。这是一个根本的不匹配,没有多少转化可以让你轻松通过。

用一个非编程类比,你不能通过同时将一个人从新加坡送到英国和另一个人从澳大利亚到新加坡来让一个人从澳大利亚到英国。

或者在编程中,如果您正在处理实时数据流,则无法通过在不增加延迟的情况下同时处理现在的数据和五分钟前的数据来并行化它。

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

于 2012-10-12T13:07:18.810 回答