Scala中的asynchronousIO与期货

比方说,我正在从某些url上下载(可能很大)的图片列表。 我正在使用Scala,所以我会做的是:

import scala.actors.Futures._ // Retrieve URLs from somewhere val urls: List[String] = ... // Download image (blocking operation) val fimages: List[Future[...]] = urls.map (url => future { download url }) // Do something (display) when complete fimages.foreach (_.foreach (display _)) 

我对Scala有点新鲜,所以对我来说这仍然有点像魔术:

  • 这是正确的做法吗? 任何替代品,如果不是?
  • 如果我有100个图像下载,这将创build100个线程一次,或将使用线程池?
  • 最后一条指令( display _ )是否会在主线程上执行,如果没有,我怎么确定它?

谢谢你的build议!

在Scala 2.10中使用期货。 他们是Scala团队,Akka团队和Twitter之间的联合工作,以达到更为标准化的未来API和实现,以便跨框架使用。 我们只是在http://docs.scala-lang.org/overviews/core/futures.html发表了一个指南;

除了完全无阻塞(默认情况下,尽pipe我们提供了执行pipe理阻塞操作的能力)和可组合的,Scala的2.10版本还带有隐式线程池来执行您的任务,还有一些实用程序来pipe理超时。

 import scala.concurrent.{future, blocking, Future, Await, ExecutionContext.Implicits.global} import scala.concurrent.duration._ // Retrieve URLs from somewhere val urls: List[String] = ... // Download image (blocking operation) val imagesFuts: List[Future[...]] = urls.map { url => future { blocking { download url } } } // Do something (display) when complete val futImages: Future[List[...]] = Future.sequence(imagesFuts) Await.result(futImages, 10 seconds).foreach(display) 

上面,我们首先导入一些东西:

  • future :创造未来的API。
  • blocking :pipe理阻止的API。
  • Future :未来伴侣对象,其中包含一些有用的方法收集期货。
  • Await :用于阻塞未来的单体对象(将其结果传输到当前线程)。
  • ExecutionContext.Implicits.global :默认的全局线程池,一个ForkJoin池。
  • duration._ :用于pipe理超时duration._实用程序。

imagesFuts基本上与您原来imagesFuts基本相同 – 这里唯一的区别是我们使用受pipe理的阻止blocking 。 它会通知线程池您传递给它的代码块包含长时间运行或阻塞操作。 这样可以让游泳池临时产生新的工人,以确保所有的工人都不会被堵塞。 这样做是为了防止阻塞应用程序中的饥饿(locking线程池)。 请注意,线程池还知道何时pipe理的阻塞块中的代码已完成,因此它将在此时删除备用工作线程,这意味着该池将缩小到预期的大小。

(如果你想完全防止创build额外的线程,那么你应该使用一个AsyncIO库,比如Java的NIO库。)

然后,我们使用Future companion对象的集合方法将List[Future[...]]中的imagesFuts转换为Future[List[...]]

Await对象是我们如何确保在调用线程上执行display Await.result只是强制当前线程等待,直到它传递的未来完成。 (这在内部使用受pipe理的阻止。)

 val all = Future.traverse(urls){ url => val f = future(download url) /*(downloadContext)*/ f.onComplete(display)(displayContext) f } Await.result(all, ...) 
  1. 在2.10中使用scala.concurrent.Future,现在是RC。
  2. 它使用一个隐含的ExecutionContext
  3. 新的Future文档明确指出,如果该值可用,onComplete(和foreach)可以立即评估。 老演员未来也做同样的事情。 根据您的要求显示,您可以提供一个合适的ExecutionContext(例如,一个线程执行程序)。 如果你只是想让主线程等待加载完成,遍历会给你一个未来的等待。
  1. 是的,对我来说似乎很好,但是你可能想要研究更强大的twitter-util或者Akka Future API(Scala 2.10将会有一个新的Future库)。

  2. 它使用一个线程池。

  3. 不,不会的 您需要使用GUI工具包的标准机制( SwingUtilities.invokeLater或SWT的Display.asyncExec )。 例如

     fimages.foreach (_.foreach(im => SwingUtilities.invokeLater(new Runnable { display im })))