scala已经配备了自身的Future类。我们先举个例子来了解scala Future的具体操作:
import scala.concurrent._
import ExecutionContext.Implicits.global
object scalafuture {
def dbl(i: Int): Future[Int] = Future { Thread.sleep(1000) ; i + i }
//> dbl: (i: Int)scala.concurrent.Future[Int]
val fdbl = dbl(3) //> fdbl : scala.concurrent.Future[Int] = List()
fdbl.onSuccess {
case a => println(s"${a/2} + ${a/2} = $a")
}
println("calculating ...") //> calculating ...
Thread.sleep(2000) //> 3 + 3 = 6
}
val fdz = Future { 3 / 0 } //> fdz : scala.concurrent.Future[Int] = List()
fdz.onFailure {
case e => println(s"error message {${e.getMessage}}")
}
Thread.sleep(100) //> error message {/ by zero}
又或者同时绑定运算成功和失败事件的callback函数:
import scala.util.{Success, Failure}
fdz onComplete {
case Success(a) => println(s"${a/2} + ${a/2} = $a")
case Failure(e) => println(s"error message {${e.getMessage}}")
}
Thread.sleep(100) //> error message {/ by zero}
scala Future 实现了flatMap,我们可以把几个Future组合起来用:
def dbl(i: Int): Future[Int] = Future { Thread.sleep(1000); i + i }
//> dbl: (i: Int)scala.concurrent.Future[Int]
def sqr(i: Int): Future[Int] = Future { i * i } //> sqr: (i: Int)scala.concurrent.Future[Int]
def sum(a: Int, b: Int): Future[Int] = Future { a + b }
//> sum: (a: Int, b: Int)scala.concurrent.Future[Int]
val fsum = for {
a <- dbl(3)
b <- sqr(a)
c <- sum(a,b)
} yield c //> fsum : scala.concurrent.Future[Int] = List()
fsum onSuccess { case c => println(s"the combined result is: $c") }
Thread.sleep(2000) //> the combined result is: 42
好了,既然scala Future的功能已经比较完善了,那么scalaz的Future又有什么不同的特点呢?首先,细心一点可以发现scala Future是即时运算的,从下面的例子里可以看出:
import scala.concurrent.duration._
val fs = Future {println("run now..."); System.currentTimeMillis() }
//> run now...
//| fs : scala.concurrent.Future[Long] = List()
Await.result(fs, 1.second) //> res0: Long = 1465907784714
Thread.sleep(1000)
Await.result(fs, 1.second) //> res1: Long = 1465907784714
sealed abstract class Future[+A] {
...
object Future {
case class Now[+A](a: A) extends Future[A]
case class Async[+A](onFinish: (A => Trampoline[Unit]) => Unit) extends Future[A]
case class Suspend[+A](thunk: () => Future[A]) extends Future[A]
case class BindSuspend[A,B](thunk: () => Future[A], f: A => Future[B]) extends Future[B]
case class BindAsync[A,B](onFinish: (A => Trampoline[Unit]) => Unit,
f: A => Future[B]) extends Future[B]
...
def flatMap[B](f: A => Future[B]): Future[B] = this match {
case Now(a) => Suspend(() => f(a))
case Suspend(thunk) => BindSuspend(thunk, f)
case Async(listen) => BindAsync(listen, f)
case BindSuspend(thunk, g) =>
Suspend(() => BindSuspend(thunk, g andThen (_ flatMap f)))
case BindAsync(listen, g) =>
Suspend(() => BindAsync(listen, g andThen (_ flatMap f)))
}
free structure类型可以支持算式/算法关注分离,也就是说我们可以用scalaz Future来描述程序功能而不涉及正真运算。scalaz Future的构建方式如下:
import scalaz._
import Scalaz._
import scalaz.concurrent._
import scala.concurrent.duration._
object scalazFuture {
val fnow = Future.now {println("run..."); System.currentTimeMillis()}
//> run...
//| fnow : scalaz.concurrent.Future[Long] = Now(1465909860301)
val fdelay = Future.delay {println("run..."); System.currentTimeMillis()}
//> fdelay : scalaz.concurrent.Future[Long] = Suspend(<function0>)
val fapply = Future {println("run..."); System.currentTimeMillis()}
//> fapply : scalaz.concurrent.Future[Long] = Async(<function1>)
fdelay.run //> run...
//| res0: Long = 1465910524847
Thread.sleep(1000)
fdelay.run //> run...
//| res1: Long = 1465910525881
fapply.run //> run...
//| res2: Long = 1465910525883
Thread.sleep(1000)
fapply.run //> run...
//| res3: Long = 1465910526884
scalaz Future只有在运算时才会产生副作用,而且可以多次运算。
我们可以用即时(blocking)、异步、定时方式来运算Future:
fapply.unsafePerformSync //> run...
//| res4: Long = 1465958049118
fapply.unsafePerformAsync {
case a => println(a)
}
Thread.sleep(1000)
fapply.unsafePerformSyncFor(1 second) //> run...
//| 1465958051126
//| run...
//| res5: Long = 1465958052172
/**
* Create a `Future` from an asynchronous computation, which takes the form
* of a function with which we can register a callback. This can be used
* to translate from a callback-based API to a straightforward monadic
* version. See `Task.async` for a version that allows for asynchronous
* exceptions.
*/
def async[A](listen: (A => Unit) => Unit): Future[A] =
Async((cb: A => Trampoline[Unit]) => listen { a => cb(a).run })
/** Create a `Future` that will evaluate `a` using the given `ExecutorService`. */
def apply[A](a: => A)(implicit pool: ExecutorService = Strategy.DefaultExecutorService): Future[A] = Async { cb =>
pool.submit { new Callable[Unit] { def call = cb(a).run }}
}
/** Create a `Future` that will evaluate `a` after at least the given delay. */
def schedule[A](a: => A, delay: Duration)(implicit pool: ScheduledExecutorService =
Strategy.DefaultTimeoutScheduler): Future[A] =
Async { cb =>
pool.schedule(new Callable[Unit] {
def call = cb(a).run
}, delay.toMillis, TimeUnit.MILLISECONDS)
}
如果我们需要模仿scala Future的功效可以用unsafeStart:
val fs = fapply.unsafeStart //> run...
//| fs : scalaz.concurrent.Future[Long] = Suspend(<function0>)
fs.run //> res6: Long = 1465958922401
Thread.sleep(1000)
fs.run //> res7: Long = 1465958922401
def fu(t: Long): Future[String] =
Future.async[String]{k => k(s"the curreent time is: ${t.toString}!!!")}
//> fu: (t: Long)scalaz.concurrent.Future[String]
fu(System.currentTimeMillis()).run //> res8: String = the curreent time is: 1465958923415!!!
import scala.concurrent.{Future => sFuture}
import scala.concurrent.ExecutionContext
import scala.util.{Success,Failure}
def futureTozFuture[A](sf: sFuture[A])(implicit ec: ExecutionContext): Future[A] =
Future.async {cb => sf.onComplete {
case Success(a) => cb(a)
// case Failure(e) => cb(e)
}} //> futureTozFuture: [A](sf: scala.concurrent.Future[A])(implicit ec: scala.con
//| current.ExecutionContext)scalaz.concurrent.Future[A]
def zFutureTosFuture[A](zf: Future[A]): sFuture[A] = {
val prom = scala.concurrent.Promise[A]
zf.unsafePerformAsync {
case a => prom.success(a)是
}
prom.future
}
我们用上面scala Future的例子来示范scalaz Future的函数组合能力:
def dbl(i: Int): Future[Int] = Future { i + i } //> dbl: (i: Int)scalaz.concurrent.Future[Int]
def sqr(i: Int): Future[Int] = Future { i * i } //> sqr: (i: Int)scalaz.concurrent.Future[Int]
def sum(a: Int, b: Int): Future[Int] = Future { a + b }
//> sum: (a: Int, b: Int)scalaz.concurrent.Future[Int]
val fsum = for {
a <- dbl(3)
b <- sqr(a)
c <- sum(a,b)
} yield c //> fsum : scalaz.concurrent.Future[Int] = BindAsync(<function1>,<function1>)
fsum.unsafePerformAsync {
case a => println(s"result c is:$a")
}
Thread.sleep(1000) //> result c is:42