我们可以在Scala中定义一组DSL操作,它们彼此并行执行,就像在Linux中使用管道处理一样

时间:2012-01-17 08:41:10

标签: scala parallel-processing

请原谅我英语不好但我会尽力表达我的问题。

假设我想处理一个大文本,其操作是通过关键字过滤内容;把它们改成小写;然后将它们打印到标准输出上。众所周知,我们可以使用Linux BASH脚本中的管道执行此操作:

cat article.txt | grep "I" | tr "I" "i" > /dev/stdout

其中cat article.txtgrep "I"tr "I" "i" > /dev/stdout并行运行。

在Scala中,我们可能会这样做:

//or read from a text file , e.g. article.txt 
val strList = List("I", "am", "a" , "student", ".", "I", "come", "from", "China", ".","I","love","peace")  
strList.filter( _ == "I").map(_.toLowerCase).foreach(println)

我的问题是如何让filtermapforeach平行?

THX

5 个答案:

答案 0 :(得分:2)

在2.9中,添加了并行集合。要并行化循环,您所要做的就是通过调用par成员函数来转换它。

您的代码如下所示:

val strList = List("I", "am", "a" , "student", ".", "I", "come", "from", "China", ".","I","love","peace")  // or read from a text file , e.g. article.txt 
strList.par.filter( _ == "I").map(_.toLowerCase).foreach(println)

答案 1 :(得分:2)

如果您将List更改为Iterator,您将看到filter / map / foreach不再分组。

试试这个:

val strList = Iterator("I", "am", "a" , "student", ".", "I", "come", "from", "China", ".","I","love","peace")  
strList.filter{ s => println("f"); s == "I"}.map{s => println("m"); s.toLowerCase}.foreach{s =>println("p")}

你会看到:
F 米 p F F F F F 米 p F F F F F 米 p F ˚F

而不是: F F F F F F F F F F F F F 米 米 米 p p P

因为当您将转换应用于List时,它立即返回一个新的List。但是当将转换应用于迭代器时,它只会在遍历它时运行(在这种情况下使用foreach)。

答案 2 :(得分:2)

在您的情况下,tstenner的解决方案可能是最有效的解决方案,因为它可以实现高度的并行性(理论上可以并行处理每个单项)。但是,你的bash示例只是使用管道并行性,遗憾的是,Scalas并行集合并不直接支持这种并行性。

要实现管道并行性,您的运算符(filter,map,foreach)必须由不同的线程执行,例如,使用Actors。

总的来说,我认为Scala有一个很好的功能就是拥有一个简单的API。但是,对于您的示例,我怀疑管道并行性会加快您的执行时间。如果你只是使用非常简单的过滤器和映射操作,我假设通信开销(对于FIFO / Actor邮箱)消耗了并行执行的整个加速。

答案 3 :(得分:2)

使用视图:

val strList = List("I", "am", "a" , "student", ".", "I", "come", "from", "China", ".","I","love","peace")  // or read from a text file , e.g. article.txt 
strList.view.filter( _ == "I").map(_.toLowerCase).foreach(println)

视图存储对集合(本例中为filtermap)的操作,并仅在您从它们请求元素时执行它们(在这种情况下为foreach)。首先,它会应用过滤器并映射到“I”,然后映射到“am”,依此类推。

答案 4 :(得分:0)

为您的函数链中的单个参数创建一个函数。然后将此函数应用于并行集合。请注意,println不会按原始集合的顺序调用。

def fmp(xs: Seq[String]){
  xs.par.foreach{x => 
    for(
      kw <- Option(x).filter(_ == "I"); 
      lc <- kw.map(_.toLowerCase)
    ) println(lc)
  }
}