【问题标题】:How to spawn an unknown amount of Futures and combine the result even if one or more failed?即使一个或多个失败,如何产生未知数量的期货并组合结果?
【发布时间】:2016-12-18 03:57:01
【问题描述】:

我想使用 Futures 将以下顺序代码转换为并发代码,并且需要有关如何构建它的建议。

顺序:

import java.net.URL

val providers = List(
  new URL("http://www.cnn.com"),
  new URL("http://www.bbc.co.uk"),
  new URL("http://www.othersite.com")
)

def download(urls: URL*) = urls.flatMap(url => io.Source.fromURL(url).getLines).distinct

val res = download(providers:_*)

我想下载通过下载方法的可变参数传入的所有源,并将结果组合到一个 Seq/List/Set 中,无论如何,一起。当一个 Future 失败时,假设因为服务器无法访问,它应该接受所有其他的并继续前进并返回结果。 firstCompletedOf 不起作用,因为我需要所有结果,除了一个因错误而失败的结果。我想过像下面那样使用 Future.sequence ,但我无法让它工作。这是我尝试过的...

def download(urls: URL*) = Future.sequence {
  urls.map { url =>
    Future {
      io.Source.fromURL(url).getLines
    }
  }
} 

这会产生一个与 M_[Future[A_]] 不兼容的 Seq[Future[Iterator[String]]]。

A Future[Iterator[String]] 是我想要的。 (我以为我返回了一个迭代器,因为我需要稍后在迭代器上使用 reset 方法重用它。)

【问题讨论】:

  • 您希望Iterator[String] 成为 URL 的扁平化结果?

标签: scala future


【解决方案1】:

你可以使用parallel collections:

import java.net.URL

val providers = List(
  new URL("http://www.cnn.com"),
  new URL("http://www.bbc.co.uk"),
  new URL("http://www.othersite.com")
)

def download(urls: URL*) = urls.par.flatMap(url => {
  Try {
    io.Source.fromURL(url).getLines
  } match {
    case Success(e) => e
    case Failure(_) => Seq()
  }
}).toSeq

val res: Seq[String] = download(providers:_*)

或者如果您想要带有Future 的非阻塞版本:

def download(urls: URL*) = Future {
  blocking {
    urls.par.flatMap(url => {
      Try {
        io.Source.fromURL(url).getLines
      } match {
        case Success(e) => e
        case Failure(_) => Seq()
      }
    })
  }
}

val res: Future[Seq[String]] = download(providers:_*)

【讨论】:

  • Future-example 不是非阻塞的,它只是异步的。
  • @ViktorKlang 下载方式是非阻塞的。通过io.Source.fromURL 获取的过程。是同步的。这里根本没有“异步”。发送 HTTP 请求是一个自然的异步操作,这里根本不需要线程,但这就是 OP 正在使用的。
  • download 是异步的,因为它将在工作执行之前返回(一个 Future)。由于 Future.apply 的工作需要调用一个阻塞方法(fromURL(...).getLines),这意味着如果 ExecutionContext 同步运行,则该方法会阻塞调用者,否则它将阻塞执行逻辑的线程。因此它不是非阻塞的(某些线程将被阻塞)并且它是异步的,可能是并发的并且使用并行化结构。 (免责声明:我是 Scala 标准库中 Scala Futures 的主要作者)
  • @ViktorKlang 我知道你是谁 :)。 download 是“假异步”。它使用阻塞方法fromURL 来执行实际上本质上是异步的的工作,就像通过网络发送请求一样。它对消费者来说是非阻塞的,但在内部它正在消耗一个 ExecutionContext 线程来阻塞它真正不应该的工作。我们之前在 twitter 上讨论过 :),我说 Java/Scala 缺少一个告诉调用者“这实际上是一个 IO 完成”的结构。
  • 不,它不是“假异步”:它要么同步执行(同步 EC,非常不鼓励)要么是异步的(在工作完成之前返回)。如果是前者,那么它会阻塞调用者线程,如果是后者,那么它会阻塞一个 EC 线程。无论如何,它都会阻止 something :)
猜你喜欢
  • 2019-09-01
  • 2011-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多