Future
2015-11-18
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