bigbully +

Future

Future

在使用Akka开发的时候会经常遇到对一个Actor发起请求,并等待接收响应。应对这种场景,最常见的方式是使用Future。

异步阻塞方式:

import scala.concurrent.Await
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._

implicit val timeout = Timeout(5 seconds)
val future = actor ? msg // enabled by the “ask” import
val result = Await.result(future, timeout.duration).asInstanceOf[String]

异步非阻塞方式:

import scala.concurrent.Future
import akka.pattern.ask

val future: Future[String] = ask(actor, msg).mapTo[String]

scala的Future与java的Future相同的地方是都需要引入线程池,不过scala的引入方式不同:

//测试时使用
import scala.concurrent.ExecutionContext.Implicits.global 

//可以通过声明隐式参数的方式
implicit val ec = ExecutionContext.fromExecutorService(yourExecutorServiceGoesHere)

//actor内部通过引入context.dispatcher使用dispatcher的线程池处理Future
class A extends Actor {
  import context.dispatcher
  val f = Future("hello")
  def receive = {
    // receive omitted ...
  }
}

可以看出Future在scala中实际上是一种数据结构(容器),用来进行异步处理(阻塞/非阻塞)。最终返回处理结果或异常。

直接使用:

import scala.concurrent.Await
import scala.concurrent.Future
import scala.concurrent.duration._

val future = Future {
  "Hello" + "World"
}
future foreach println

如果已知Future的结果:

val future = Future.successful("Yay!")

val otherFuture = Future.failed[String](new IllegalArgumentException("Bang!"))

事实上Future也是scala实现的众多Monad(单子)中的一种。

btw,什么是Monad?

tip A monad is an implementation of one of the minimal sets of monadic combinators, satisfying the laws of associativity(结合律) and identity(单位元).------《functional programming in scala》

map, foreach:

val f1 = Future {
  "Hello" + "World"
}
val f2 = f1 map { x ⇒
  x.length
}
f2 foreach println

flatMap:

val f1 = Future {
  "Hello" + "World"
}
val f2 = Future.successful(3)
val f3 = f1 flatMap { x ⇒
  f2 map { y ⇒
    x.length * y
  }
}
f3 foreach println

filter:

val future1 = Future.successful(4)
val future2 = future1.filter(_ % 2 == 0)

future2 foreach println

For Comprehensions:

val f = for {
  a ← Future(10 / 2) // 10 / 2 = 5
  b ← Future(a + 1) //  5 + 1 = 6
  c ← Future(a - 1) //  5 - 1 = 4
  if c > 3 // Future.filter
} yield b * c //  6 * 4 = 24

// Note that the execution of futures a, b, and c
// are not done in parallel.

f foreach println

应用For Comprehensions需要注意的,例1和例2的区别:

例1:

val f = for {
  a ← Future(10 / 2)
  b ← Future(2 * 3) 
} yield a * b 

f foreach println

例2:

val f1 = Future(10 / 2)
val f2 = Future(2 * 3) 

val f = for {
  a ← f1 
  b ← f2 
} yield a * b 

f foreach println