00010 Scala Futures Promise

在scala中可以方便的实现异步操作,这里是通过Future来实现的,和java中的Future很相似,但是功能更加强大。

定义返回Future的方法

下面我们看下如何定义一个返回Future的方法:

println("Step 1: Define a method which returns a Future")
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
def donutStock(donut: String): Future[Int] = Future {
  // assume some long running database operation
  println("checking donut stock")
  10
}

注意这里需要引入scala.concurrent.ExecutionContext.Implicits.global, 它会提供一个默认的线程池来异步执行Future。

阻塞方式获取Future的值

  println("\nStep 2: Call method which returns a Future")
  import scala.concurrent.Await
  import scala.concurrent.duration._
  val vanillaDonutStock = Await.result(donutStock("vanilla donut"), 5 seconds)
  println(s"Stock of vanilla donut = $vanillaDonutStock")

donutStock() 是异步执行的,我们可以使用Await.result() 来阻塞主线程来等待donutStock()的执行结果。

下面是其输出:

非阻塞方式获取Future的值

我们可以使用Future.onComplete() 回调来实现非阻塞的通知:

Future.onComplete() 有两种可能情况,Success 或者 Failure,需要引入: import scala.util.{Failure, Success}

Future链

有时候我们需要在获得一个Future之后再继续对其进行操作,有点类似于java中的管道,下面看一个例子:

上面我们又定义了一个方法,用来接收donutStock()的返回值,然后再返回一个Future[Boolean]

我们看下使用flatmap该怎么链接他们:

同样的,我们还可以使用for语句来进行链接:

flatmap VS map

map就是对集合中的元素进行重映射,而flatmap则会将返回的值拆散然后重新组合。 下面举个直观的例子:

flatMap返回的值是Future[Boolean]

map返回的值是Future[Future[Boolean]]

Future.sequence() VS Future.traverse()

如果我们有很多个Future,然后想让他们并行执行,则可以使用 Future.sequence() 。

Future.traverse() 和Future.sequence() 类似, 唯一不同的是,Future.traverse()可以对要执行的Future进行操作,如下所示:

Future.foldLeft VS Future reduceLeft

foldLeft 和 reduceLeft 都是用来从左到右做集合操作的,区别在于foldLeft可以提供默认值。看下下面的例子:

输出结果:

输出结果:

Future firstCompletedOf

firstCompletedOf在处理多个Future请求时,会返回第一个处理完成的future结果。

Future zip VS zipWith

zip用来将两个future结果组合成一个tuple. zipWith则可以自定义Function来处理future返回的结果。

输出值:

使用zipwith的例子:

输出结果:

Future andThen

andThen后面可以跟一个自定义的PartialFunction,来处理Future返回的结果, 如下所示:

输出结果:

自定义threadpool

上面的例子中, 我们都是使用了scala的全局ExecutionContext: scala.concurrent.ExecutionContext.Implicits.global. 同样的,我们也可以自定义你自己的ExecutionContext。下面是一个使用java.util.concurrent.Executors的例子:

recover() recoverWith() and fallbackTo()

这三个方法主要用来处理异常的,recover是用来从你已知的异常中恢复,如下所示:

recoverWith()和recover()类似,不同的是他的返回值是一个Future。

fallbackTo()是在发生异常时,去调用指定的方法:

promise

熟悉ES6的同学可能知道,promise是JS在ES6中引入的新特性,其主要目的是将回调转变成链式调动。

当然scala的promise和ES6的promise还是不一样的,我们看下scala中promise是怎么用的:

上面例子中我们使用了 Promise.successPromise.failurePromise.complete() 来控制程序的运行。

最后更新于

这有帮助吗?