首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Scala并行文件下载

Scala并行文件下载
EN

Stack Overflow用户
提问于 2016-10-19 16:05:24
回答 2查看 468关注 0票数 0

假设我有一个URL列表和一个下载相应文件的函数:

代码语言:javascript
复制
val urls = List(url1, url2, url3)
def fetch(url: String): File = ...

我想知道有没有比这更好的并行下载这些文件的方法:

代码语言:javascript
复制
val futureFiles: Future[List[File]] = Future {
  urls.par.map(fetch)
}
futureFiles.map(files => ...)

我看到的一个问题是,现在我只能在所有文件都下载后才能访问它们。如何做到如此简洁和优雅,并且能够在下载的每个文件上执行操作?

EN

回答 2

Stack Overflow用户

发布于 2016-10-19 16:11:04

这样如何:

代码语言:javascript
复制
urls.par.map(fetch).map(file => ...)

以这种方式,获取和“处理”所获取的文件是并行完成的。

票数 2
EN

Stack Overflow用户

发布于 2016-10-19 18:32:13

...a并行下载这些文件的更好方法...

这取决于你所说的“并行下载这些文件”到底是什么意思。假设您想要下载三个文件(基于示例:val urls = List(url1, url2, url3))。这可能意味着两件不同的事情:

  • 只是将下载从当前线程移走,而不关心下载本身是并行执行还是顺序执行(因此,url1可能在url2之前获取,然后是url3),将下载从当前线程移走,并并行执行下载本身(所有urls都同时获取)。

如果第一个选项是您想要的,那么Tzach Zohar提供的答案是一个很好的方法。并行收集将把您的urls放在分区中,并为每个分区分配一个线程。如果你有3个元素,你的下载很可能是按顺序进行的,因为只有一个分区。如果您的urls的List更大,那么您也将获得更多的线程,但每个分区中的urls仍将按顺序获取。

如果你想同时下载所有文件(选项2),那么你需要对并行性进行更多的控制。您的Future方法并没有那么错误,但是您需要为每个Future提供一个Future,而不是将整个下载过程放在一个url中。

您的代码可能如下所示:

代码语言:javascript
复制
val futureFiles: List[Future[File]] = urls.map(u => Future(fetch(u))) // note: no par

请注意,您现在得到的是List[Future[File]],而不是以前的Future[List[File]]。随后,您可以分别映射到每个Future,而不必等待一个Future完成(就像以前一样)。

代码语言:javascript
复制
futureFiles.map(_.map(file => ...))

之后,您可以选择使用Future.sequence将生成的List[Future[T]]转换为Future[List[T]]

您必须确保使用正确配置的ExecutionContext,否则,您的部分下载可能仍会按顺序执行。除此之外,用一些真正异步的东西替换你的阻塞IO是个好主意(参见insan-e的评论)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40125555

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档