在Scala 2.10中使用Futures。它们是Scala团队,Akka团队和Twitter共同开发的,旨在实现更标准化的未来API和实现,以供各种框架使用。我们刚刚发布了一份指南: http://docs.scala-lang.org/overviews/core/futures.html
除了完全非阻塞(默认情况下,尽管我们提供管理阻塞操作的能力)和可以组合,Scala 2.10 Futures还带有一个隐式线程池来执行您的任务,以及一些工具来管理超时。
import scala.concurrent.{future, blocking, Future, Await, ExecutionContext.Implicits.global}
import scala.concurrent.duration._
val urls: List[String] = ...
val imagesFuts: List[Future[...]] = urls.map {
url => future { blocking { download url } }
}
val futImages: Future[List[...]] = Future.sequence(imagesFuts)
Await.result(futImages, 10 seconds).foreach(display)
首先,我们导入了许多内容:
future
:用于创建future的API。
blocking
:用于管理阻塞的API。
Future
:包含许多有用的方法用于future的集合的未来伴随对象。
Await
:单例对象,用于阻塞未来(将其结果传输到当前线程)。
ExecutionContext.Implicits.global
:默认的全局线程池,一个ForkJoin池。
duration._
:用于管理超时时间的实用程序。
imagesFuts
基本上与您最初做的相同- 这里唯一的区别是我们使用了受管阻塞 - blocking
。它会通知线程池,您传递给它的代码块包含长时间运行或阻塞操作。这允许池临时生成新的工作程序以确保永远不会发生所有工作程序都被阻塞的情况。这样做是为了防止在阻塞应用程序中发生饥饿(锁定线程池)。请注意,当受管阻塞块中的代码完成时,线程池也会知道-因此它将在那一点上删除多余的工作线程,这意味着池将缩小到其预期大小。
(如果您希望绝对防止创建其他线程,则应使用AsyncIO库,例如Java的NIO库。)
然后,我们使用Future伴随对象的集合方法,将imagesFuts
从List[Future[...]]
转换为Future[List[...]]
。
Await
对象是我们如何确保display
在调用线程上执行-- Await.result
只需强制当前线程等待传递给它的future完成即可。(这在内部使用受管阻塞。)
ExecutionContext
,例如使用Swing的invokeLater
,并将其明确传递给futImages
上的foreach
,而不是使用Await.result
。 - Heather Millerblocking
背后的机制是如何工作的?它是否有自己的线程池,还是在我们通过blocking
提交任务时会创建新的线程? - maksurl => future { blocking { download url } }
中要使用阻塞,而不是只使用url => future { download url }
? - Incerteza