Scala 如何产生未知数量的未来,并在一个或多个失败的情况下合并结果?

Scala 如何产生未知数量的未来,并在一个或多个失败的情况下合并结果?,scala,future,Scala,Future,我想将下面的顺序代码转换为具有未来的并发代码,并需要关于如何构造它的建议 顺序: 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.Sour

我想将下面的顺序代码转换为具有未来的并发代码,并需要关于如何构造它的建议

顺序:

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:_*)
我想下载通过下载方法的varargs输入的所有源代码,并将结果合并到一个Seq/List/Set中,不管是什么。当一个未来失败时,比如说因为服务器不可访问,它应该继续运行并返回结果firstCompletedOf不起作用,因为我需要所有结果,只有一个由于错误而失败。我曾想过使用如下所示的Future.sequence,但我无法让它工作。这是我试过的

def download(urls: URL*) = Future.sequence {
  urls.map { url =>
    Future {
      io.Source.fromURL(url).getLines
    }
  }
} 
这将生成一个Seq[Future[Iterator[String]]],它与M_u3;[Future[a_3;]]不兼容

我想要的是未来的[迭代器[字符串]]。(我想我返回了一个迭代器,因为我以后需要用迭代器上的reset方法重用它。)

您可以使用:

或者,如果您希望非阻塞版本具有
未来

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:_*)

您想将迭代器[String]作为URL的展平结果吗?未来的示例不是非阻塞的,它只是异步的。@ViktorKlang下载方法是非阻塞的。通过
io.Source.fromURL
获取过程。是同步的。这里根本没有“异步”。发送HTTP请求是一种自然的异步操作,这里根本不需要线程,但OP就是这样使用的。
download
是异步的,因为它将在工作执行之前返回(将来)。由于Future.apply的工作需要调用一个阻塞方法(fromURL(…).getLines),这意味着如果ExecutionContext同步运行,那么该方法将阻塞调用者,否则它将阻塞执行逻辑的线程。因此,它不是非阻塞的(某些线程将被阻塞),它是异步的,可能是并发的,并且使用并行化结构。(免责声明:我是Scala标准库中Scala Futures的主要作者)@ViktorKlang我知道你是谁:)<代码>下载是“伪异步”。它使用阻塞方法
fromURL
来执行本质上是异步的工作,就像通过线路发送请求一样。它对使用者来说是非阻塞的,但在内部它使用一个ExecutionContext线程来阻塞它实际上不应该阻塞的工作。我们之前在twitter上讨论过:),我说Java/Scala缺少一个告诉调用方“这实际上是一个IO完成”的结构。不,它不是“伪异步”:它要么同步执行(sync EC,高度不鼓励),要么异步执行(在工作完成之前返回)。如果前者阻止调用线程,如果后者阻止EC线程。不管怎样,它都会阻止某些内容:)
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:_*)