3

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

据我了解,我有两种选择:

与期货并行的方式

我有一个在 Future 中提取一些 JSON 数据的方法:

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

我只是将它映射到链接列表上,该类型将是 List[Future[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,我只是不能在这里使用演员,所以只能FuturePar*

4

1 回答 1

5

当您映射集合时,这些链接被并行处理。extractData考虑一个稍微简化的例子:

import scala.concurrent._
import ExecutionContext.Implicits.global

def extractData(s: String) = future {
  printf("Starting: %s\n", s)
  val i = s.toInt
  printf("Done: %s\n", 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 解析,并且文档中充满了如何使用期货的有用示例。

于 2013-08-14T17:39:41.980 回答