请原谅我英语不好但我会尽力表达我的问题。
假设我想处理一个大文本,其操作是通过关键字过滤内容;把它们改成小写;然后将它们打印到标准输出上。众所周知,我们可以使用Linux BASH脚本中的管道执行此操作:
cat article.txt | grep "I" | tr "I" "i" > /dev/stdout
其中cat article.txt
,grep "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)
我的问题是如何让filter
,map
和foreach
平行?
THX
答案 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)
要实现管道并行性,您的运算符(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)
视图存储对集合(本例中为filter
和map
)的操作,并仅在您从它们请求元素时执行它们(在这种情况下为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)
}
}