并行计算/解析列表元素(链接)



无法理解并行计算列表元素的正确方法,但在不计算元素(并行)时阻塞主线程。用例:我有一个URL链接列表和一个简单的html页面解析器,我想通过并行解析每个页面来减少从给定页面获取信息所需的时间,然后返回一个包含一些JSON数据的简单列表。

据我所知,我有两个选择:

与期货并行

我有一种在未来提取一些JSON数据的方法:

def extractData(link: String): Future[JValue] = // some implementation

我只是把它映射到一个链接列表上,类型是list[Foret[JValue]]:

val res: List[Future[JValue]] = listOfLink.map(extractData)

如果我调用sequence(例如,从Scalaz或我自己的实现),它遍历这个列表并将其转换为Future[List[JValue]],那么链接仍将按顺序处理,但单独的线程不会给我任何效率,因为结果我需要获得List[JValue]

尝试使用ParSeq进行计算

在这个选项中,我有一个只提取数据的功能:

def extractData(link: String): JValue = // some implementation

但这次调用集合上的.par

val res: ParSeq[JValue] = listOfLinks.map(extractData)

但是在这种方式下,我不太明白如何在不按顺序解析每个链接的情况下,在不计算孔列表的情况下阻塞主线程

至于Akka,我不能在这里使用actor,所以只有FuturePar*

在集合上映射extractData时,链接将被并行处理。考虑一个稍微简化的例子:

import scala.concurrent._
import ExecutionContext.Implicits.global
def extractData(s: String) = future {
  printf("Starting: %sn", s)
  val i = s.toInt
  printf("Done: %sn", s)
  i
}
val xs = (0 to 5).map(_.toString).toList
val parsed = Future.sequence(xs map extractData)

现在,您将看到以下内容,这清楚地表明这些内容没有按顺序处理:

Starting: 0
Done: 0
Starting: 2
Done: 2
Starting: 1
Starting: 4
Done: 1
Starting: 3
Starting: 5
Done: 5
Done: 4
Done: 3

请注意,您可以使用Future.traverse来避免创建期货的中间列表:

val parsed = Future.traverse(xs)(extractData)

在任何一种情况下,您都可以使用Await:进行阻止

val res = Await.result(parsed, duration.Duration.Inf)

作为一个脚注:我不知道你是否计划使用Dispatch来执行HTTP请求,但如果没有,那就值得一看。它还提供了良好集成的JSON解析,文档中充满了如何使用期货的有用示例。

相关内容

  • 没有找到相关文章

最新更新