scala已经配备了自身的Future类。我们先举个例子来了解scala Future的具体操作:

  1. import scala.concurrent._
  2. import ExecutionContext.Implicits.global
  3. object scalafuture {
  4. def dbl(i: Int): Future[Int] = Future { Thread.sleep() ; i + i }
  5. //> dbl: (i: Int)scala.concurrent.Future[Int]
  6. val fdbl = dbl() //> fdbl : scala.concurrent.Future[Int] = List()
  7. fdbl.onSuccess {
  8. case a => println(s"${a/2} + ${a/2} = $a")
  9. }
  10. println("calculating ...") //> calculating ...
  11. Thread.sleep() //> 3 + 3 = 6
  12. }

这是一个标准的异步运算;在成功完成运算事件上绑定callback来获取在其它线程中的运算结果。我们也可以进行异常处理:

  1. val fdz = Future { / } //> fdz : scala.concurrent.Future[Int] = List()
  2. fdz.onFailure {
  3. case e => println(s"error message {${e.getMessage}}")
  4. }
  5. Thread.sleep() //> error message {/ by zero}

又或者同时绑定运算成功和失败事件的callback函数:

  1. import scala.util.{Success, Failure}
  2. fdz onComplete {
  3. case Success(a) => println(s"${a/2} + ${a/2} = $a")
  4. case Failure(e) => println(s"error message {${e.getMessage}}")
  5. }
  6. Thread.sleep() //> error message {/ by zero}

scala Future 实现了flatMap,我们可以把几个Future组合起来用:

  1. def dbl(i: Int): Future[Int] = Future { Thread.sleep(); i + i }
  2. //> dbl: (i: Int)scala.concurrent.Future[Int]
  3. def sqr(i: Int): Future[Int] = Future { i * i } //> sqr: (i: Int)scala.concurrent.Future[Int]
  4. def sum(a: Int, b: Int): Future[Int] = Future { a + b }
  5. //> sum: (a: Int, b: Int)scala.concurrent.Future[Int]
  6. val fsum = for {
  7. a <- dbl()
  8. b <- sqr(a)
  9. c <- sum(a,b)
  10. } yield c //> fsum : scala.concurrent.Future[Int] = List()
  11.  
  12. fsum onSuccess { case c => println(s"the combined result is: $c") }
  13. Thread.sleep() //> the combined result is: 42

scala Future利用flatMap实现了流程运算:先运算dbl再sqr再sum,这个顺序是固定的即使它们可能在不同的线程里运算,因为sqr依赖dbl的结果,而sum又依赖dbl和sqr的结果。

好了,既然scala Future的功能已经比较完善了,那么scalaz的Future又有什么不同的特点呢?首先,细心一点可以发现scala Future是即时运算的,从下面的例子里可以看出:

  1. import scala.concurrent.duration._
  2. val fs = Future {println("run now..."); System.currentTimeMillis() }
  3. //> run now...
  4. //| fs : scala.concurrent.Future[Long] = List()
  5. Await.result(fs, .second) //> res0: Long = 1465907784714
  6. Thread.sleep()
  7. Await.result(fs, .second) //> res1: Long = 1465907784714

可以看到fs是在Future构建时即时运算的,而且只会运算一次。如果scala Future中包括了能产生副作用的代码,在构建时就会立即产生副作用。所以我们是无法使用scala Future来编写纯函数的,那么在scalaz里就必须为并发编程提供一个与scala Future具同等功能但又不会立即产生副作用的类型了,这就是scalaz版本的Future。我们看看scalaz是如何定义Future的:scalaz.concurrent/Future.scala

  1. sealed abstract class Future[+A] {
  2. ...
  3. object Future {
  4. case class Now[+A](a: A) extends Future[A]
  5. case class Async[+A](onFinish: (A => Trampoline[Unit]) => Unit) extends Future[A]
  6. case class Suspend[+A](thunk: () => Future[A]) extends Future[A]
  7. case class BindSuspend[A,B](thunk: () => Future[A], f: A => Future[B]) extends Future[B]
  8. case class BindAsync[A,B](onFinish: (A => Trampoline[Unit]) => Unit,
  9. f: A => Future[B]) extends Future[B]
  10. ...

Future[A]就是个Free Monad。它的结构化表达方式分别有Now,Async,Suspend,BindSuspend,BindAsync。我们可以用这些结构实现flatMap函数,所以Future就是Free Monad:

  1. def flatMap[B](f: A => Future[B]): Future[B] = this match {
  2. case Now(a) => Suspend(() => f(a))
  3. case Suspend(thunk) => BindSuspend(thunk, f)
  4. case Async(listen) => BindAsync(listen, f)
  5. case BindSuspend(thunk, g) =>
  6. Suspend(() => BindSuspend(thunk, g andThen (_ flatMap f)))
  7. case BindAsync(listen, g) =>
  8. Suspend(() => BindAsync(listen, g andThen (_ flatMap f)))
  9. }

free structure类型可以支持算式/算法关注分离,也就是说我们可以用scalaz Future来描述程序功能而不涉及正真运算。scalaz Future的构建方式如下:

  1. import scalaz._
  2. import Scalaz._
  3. import scalaz.concurrent._
  4. import scala.concurrent.duration._
  5. object scalazFuture {
  6. val fnow = Future.now {println("run..."); System.currentTimeMillis()}
  7. //> run...
  8. //| fnow : scalaz.concurrent.Future[Long] = Now(1465909860301)
  9. val fdelay = Future.delay {println("run..."); System.currentTimeMillis()}
  10. //> fdelay : scalaz.concurrent.Future[Long] = Suspend(<function0>)
  11. val fapply = Future {println("run..."); System.currentTimeMillis()}
  12. //> fapply : scalaz.concurrent.Future[Long] = Async(<function1>)

可以看到fnow是个即时运算的构建器,而这个now就是一个lift函数, 它负责把一个普通无副作用运算升格成Future。fdelay,fapply分别把运算存入trampoline进行结构化了。我们必须另外运算trampoline来运行结构内的运算:

  1. fdelay.run //> run...
  2. //| res0: Long = 1465910524847
  3. Thread.sleep()
  4. fdelay.run //> run...
  5. //| res1: Long = 1465910525881
  6. fapply.run //> run...
  7. //| res2: Long = 1465910525883
  8. Thread.sleep()
  9. fapply.run //> run...
  10. //| res3: Long = 1465910526884

scalaz Future只有在运算时才会产生副作用,而且可以多次运算。

我们可以用即时(blocking)、异步、定时方式来运算Future:

  1. fapply.unsafePerformSync //> run...
  2. //| res4: Long = 1465958049118
  3. fapply.unsafePerformAsync {
  4. case a => println(a)
  5. }
  6. Thread.sleep()
  7. fapply.unsafePerformSyncFor( second) //> run...
  8. //| 1465958051126
  9. //| run...
  10. //| res5: Long = 1465958052172

结构化状态Async代表了scalaz Future的多线程处理特性:

  1. /**
  2. * Create a `Future` from an asynchronous computation, which takes the form
  3. * of a function with which we can register a callback. This can be used
  4. * to translate from a callback-based API to a straightforward monadic
  5. * version. See `Task.async` for a version that allows for asynchronous
  6. * exceptions.
  7. */
  8. def async[A](listen: (A => Unit) => Unit): Future[A] =
  9. Async((cb: A => Trampoline[Unit]) => listen { a => cb(a).run })
  10.  
  11. /** Create a `Future` that will evaluate `a` using the given `ExecutorService`. */
  12. def apply[A](a: => A)(implicit pool: ExecutorService = Strategy.DefaultExecutorService): Future[A] = Async { cb =>
  13. pool.submit { new Callable[Unit] { def call = cb(a).run }}
  14. }
  15.  
  16. /** Create a `Future` that will evaluate `a` after at least the given delay. */
  17. def schedule[A](a: => A, delay: Duration)(implicit pool: ScheduledExecutorService =
  18. Strategy.DefaultTimeoutScheduler): Future[A] =
  19. Async { cb =>
  20. pool.schedule(new Callable[Unit] {
  21. def call = cb(a).run
  22. }, delay.toMillis, TimeUnit.MILLISECONDS)
  23. }

我们看到apply和schedule在构建Future时对运算线程进行了配置。

如果我们需要模仿scala Future的功效可以用unsafeStart:

  1. val fs = fapply.unsafeStart //> run...
  2. //| fs : scalaz.concurrent.Future[Long] = Suspend(<function0>)
  3. fs.run //> res6: Long = 1465958922401
  4. Thread.sleep()
  5. fs.run //> res7: Long = 1465958922401

我们也可以用scala Future的callback方式用async函数把自定义的callback挂在构建的Future上:

  1. def fu(t: Long): Future[String] =
  2. Future.async[String]{k => k(s"the curreent time is: ${t.toString}!!!")}
  3. //> fu: (t: Long)scalaz.concurrent.Future[String]
  4. fu(System.currentTimeMillis()).run //> res8: String = the curreent time is: 1465958923415!!!

scala Future和scalaz Future之间可以相互转换:

  1. import scala.concurrent.{Future => sFuture}
  2. import scala.concurrent.ExecutionContext
  3. import scala.util.{Success,Failure}
  4. def futureTozFuture[A](sf: sFuture[A])(implicit ec: ExecutionContext): Future[A] =
  5. Future.async {cb => sf.onComplete {
  6. case Success(a) => cb(a)
  7. // case Failure(e) => cb(e)
  8. }} //> futureTozFuture: [A](sf: scala.concurrent.Future[A])(implicit ec: scala.con
  9. //| current.ExecutionContext)scalaz.concurrent.Future[A]
  10. def zFutureTosFuture[A](zf: Future[A]): sFuture[A] = {
  11. val prom = scala.concurrent.Promise[A]
  12. zf.unsafePerformAsync {
  13. case a => prom.success(a)是
  14. }
  15. prom.future
  16. }

突然发现scalaz Future是没有异常处理(exception)功能的。scalaz提供了concurrent.Task类型填补了Future的这部分缺陷。我们会在下篇讨论Task。
我们用上面scala Future的例子来示范scalaz Future的函数组合能力:

  1. def dbl(i: Int): Future[Int] = Future { i + i } //> dbl: (i: Int)scalaz.concurrent.Future[Int]
  2. def sqr(i: Int): Future[Int] = Future { i * i } //> sqr: (i: Int)scalaz.concurrent.Future[Int]
  3. def sum(a: Int, b: Int): Future[Int] = Future { a + b }
  4. //> sum: (a: Int, b: Int)scalaz.concurrent.Future[Int]
  5. val fsum = for {
  6. a <- dbl()
  7. b <- sqr(a)
  8. c <- sum(a,b)
  9. } yield c //> fsum : scalaz.concurrent.Future[Int] = BindAsync(<function1>,<function1>)
  10.  
  11. fsum.unsafePerformAsync {
  12. case a => println(s"result c is:$a")
  13. }
  14. Thread.sleep() //> result c is:42

Scalaz(44)- concurrency :scalaz Future,尚不完整的多线程类型的更多相关文章

  1. Java多线程编程:Callable、Future和FutureTask浅析(多线程编程之四)

    java多线程-概念&创建启动&中断&守护线程&优先级&线程状态(多线程编程之一)java多线程同步以及线程间通信详解&消费者生产者模式&死锁& ...

  2. Java Concurrency - Callable & Future

    One of the advantages of the Executor framework is that you can run concurrent tasks that return a r ...

  3. 华为ENSP进行evn实验,尚不完整,但已经有RT1、RT2、RT3、RT4了

    组网R1 -- CE12800  -- CE12800 --- R2 其中R1.R2是模拟VM的 R1的配置: interface GigabitEthernet0/0/0#interface Gig ...

  4. Scalaz(50)- scalaz-stream: 安全的无穷运算-running infinite stream freely

    scalaz-stream支持无穷数据流(infinite stream),这本身是它强大的功能之一,试想有多少系统需要通过无穷运算才能得以实现.这是因为外界的输入是不可预料的,对于系统本身就是无穷的 ...

  5. Scalaz(47)- scalaz-stream: 深入了解-Source

    scalaz-stream库的主要设计目标是实现函数式的I/O编程(functional I/O).这样用户就能使用功能单一的基础I/O函数组合成为功能完整的I/O程序.还有一个目标就是保证资源的安全 ...

  6. Scalaz(53)- scalaz-stream: 程序运算器-application scenario

    从上面多篇的讨论中我们了解到scalaz-stream代表一串连续无穷的数据或者程序.对这个数据流的处理过程就是一个状态机器(state machine)的状态转变过程.这种模式与我们通常遇到的程序流 ...

  7. Scalaz(49)- scalaz-stream: 深入了解-Sink/Channel

    一个完整的scalaz-stream有以下几个部分组成:Source -> Transducer -> Sink,用直白文字来描述就是:“输入 -> 传换 -> 输出”.我们已 ...

  8. Scalaz(41)- Free :IO Monad-Free特定版本的FP语法

    我们不断地重申FP强调代码无副作用,这样才能实现编程纯代码.像通过键盘显示器进行交流.读写文件.数据库等这些IO操作都会产生副作用.那么我们是不是为了实现纯代码而放弃IO操作呢?没有IO的程序就是一段 ...

  9. Scalaz(40)- Free :versioned up,再回顾

    在上一篇讨论里我在设计示范例子时遇到了一些麻烦.由于Free Monad可能是一种主流的FP编程规范,所以在进入实质编程之前必须把所有东西都搞清楚.前面遇到的问题主要与scalaz Free的Free ...

随机推荐

  1. 谷歌大牛 Rob Pike 的 5 个编程原则

    谷歌大牛 Rob Pike 的 5 个编程原则 简介: Rob Pike,目前谷歌公司最著名的软件工程师之一,曾是贝尔实验室Unix开发团队成员,Plan9操作系统开发的主要领导人,Inferno操作 ...

  2. Atitit java的异常exception 结构Throwable类

    Atitit java的异常exception 结构Throwable类 1.1. Throwable类 2.StackTrace栈轨迹1 1.2. 3.cause因由1 1.3. 4.Suppres ...

  3. 每天一个linux命令(14):head 命令

    head 与 tail 就像它的名字一样的浅显易懂,它是用来显示开头或结尾某个数量的文字区块,head 用来显示档案的开头至标准输出中,而 tail 想当然尔就是看档案的结尾. 1.命令格式: hea ...

  4. 深入理解PHP内核(八)变量及数据类型-预定义变量

    原文链接:http://www.orlion.ga/249/ PHP脚本在执行的时候用户全局变量(在用户空间显示定义的变量)会保存在一个HashTable数据类型的符号表中(symbol_table) ...

  5. 深入理解javascript作用域系列第一篇——内部原理

    × 目录 [1]编译 [2]执行 [3]查询[4]嵌套[5]异常[6]原理 前面的话 javascript拥有一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量,这套规则被称为作用域.作用域 ...

  6. MySQL性能优化的最佳21条经验

    今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我们程序员需要去关注的事情.当我们去设计数据库表结构,对操作数据 ...

  7. 用Log Parser Studio分析IIS日志

    发现一个强大的图形化IIS日志分析工具——Log Parser Studio,下面分享一个实际操作案例. 1. 安装Log Parser Studio a) 需要先安装Log Parser,下载地址: ...

  8. Anliven - 有效阅读的方法

    讲方法,忌盲目. 阅读方法 做好眼前事 排除其他事项干扰,营造适合阅读的状态和环境,专注地投入阅读之中. 如果被一堆乱糟糟的事情烦扰,身心处于一个疲惫的状态,必然无法保持专注的阅读. 定性定量 每个人 ...

  9. CSS 魔法系列:纯 CSS 绘制各种图形《系列五》

    我们的网页因为 CSS 而呈现千变万化的风格.这一看似简单的样式语言在使用中非常灵活,只要你发挥创意就能实现很多比人想象不到的效果.特别是随着 CSS3 的广泛使用,更多新奇的 CSS 作品涌现出来. ...

  10. 2015年,从毕业到工作的几点感悟(Android开发新人)

    锄禾日当午,汗滴禾下土.       2015年,从毕业到工作的几点感悟(Android开发): 多用三方类库:(成长经验:尽量不要自己手动实现网络上已经有的优秀开源类库的功能,例如: 网络请求:常见 ...