我试图使它可选运行map
操作顺序或并行,例如使用以下代码:
val runParallel = true
val theList = List(1,2,3,4,5)
(if(runParallel) theList.par else theList) map println //Doesn't run in parallel
我注意到的是,因为我预料的“地图”操作不并行运行。 虽然没有条件,它会:
theList.par map println //Runs in parallel as visible in the output
该类型的表达式(if(runParallel) theList else theList.par)
我希望是这两种类型的最接近共同祖先theList
和theList.par
的是,我不会在这里贴上一个可怕的类型,但看起来也同样吸引在(通过控制台阶:)
:type (if(true) theList else theList.par)
为什么没有在map
上并联并行采集工作?
更新:这是在讨论SI-4843 ,但是从JIRA票,目前还不清楚为什么这对斯卡拉2.9.x.发生
为什么它发生的解释是一个很长的故事:在斯卡拉2.9.x(我不知道有关的其它版本),这些集合的方法,如过滤器或地图依赖于CanBuildFrom
机制。 这个想法是,你有被用来创建新的集合建设者的隐含参数:
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
b.sizeHint(this)
for (x <- this) b += f(x)
b.result
}
由于这种机制,地图方法仅被定义在TraversableLike
特质和它的子类不需要重写它。 正如你看到的,法图签名里边有很多类型的参数。 让我们来看看那些琐碎:
- 的
B
这是新集合中的元素的种类 - 所述
A
是元素的源集合中的类型
让我们来看看更复杂的问题:
That
是新类型的集合,这可以从目前的类型不同。 一个经典的例子是,当你使用一个toString映射例如位集合:
scala> val a = BitSet(1,3,5) a scala.collection.immutable.BitSet = BitSet(1, 3, 5) scala> a.map {_.toString} res2: scala.collection.immutable.Set[java.lang.String] = Set(1, 3, 5)
因为它是非法的创建一个BitSet[String]
地图结果将是一个Set[String]
最后Repr
是当前收集的类型。 当您尝试在映射的功能集合,编译器将解决使用类型参数的适当CanBuildFrom。
因为它是合理的,在地图上的方法已被覆盖在平行集合ParIterableLike
如下所示:
def map[S, That](f: T => S)(implicit bf: CanBuildFrom[Repr, S, That]): That = bf ifParallel { pbf =>
executeAndWaitResult(new Map[S, That](f, pbf, splitter) mapResult { _.result })
} otherwise seq.map(f)(bf2seq(bf))
正如你可以看到,该方法具有相同的签名,但它采用了不同的方法:它测试提供是否CanBuildFrom
平行否则倒在默认的实现。 因此,斯卡拉并行收集使用特殊CanBuildFrom(平行的),其创建的映射方法并行的建设者。
但是,当你这样做,会发生什么
(if(runParallel) theList.par else theList) map println //Doesn't run in parallel
在地图方法被上的结果来执行
(if(runParallel) theList.par else theList)
其返回类型为两个类的第一共同祖先(在这种情况下只是一个特定数量性状混合聚会的)。 因为它是一个共同的祖先,是类型参数Repr
将是某种形式的两个集合表示的共同祖先,让我们叫它Repr1
。
结论
当调用map
的方法,编译器应该找到一个合适的CanBuildFrom[Repr, B, That]
的操作。 由于我们的Repr1
不是平行集合的一个,也不会有任何CanBuildFrom[Repr1,B,That]
能够提供平行助洗剂。 这实际上是一个正确的行为相对于Scala集合的实现中,如果行为会有所不同,这将意味着非并行收集的每一个地图将并行运行也是如此。
这里的关键是,对于Scala集合是如何设计在2.9.x别无他法。 如果编译器不提供CanBuildFrom
的并行采集,地图将不平行。