Scalaz(44)- concurrency :scalaz Future,尚不完整的多线程类型
scala已经配备了自身的Future类。我们先举个例子来了解scala Future的具体操作:
import scala.concurrent._
import ExecutionContext.Implicits.global
object scalafuture {
def dbl(i: Int): Future[Int] = Future { Thread.sleep() ; i + i }
//> dbl: (i: Int)scala.concurrent.Future[Int]
val fdbl = dbl() //> fdbl : scala.concurrent.Future[Int] = List()
fdbl.onSuccess {
case a => println(s"${a/2} + ${a/2} = $a")
}
println("calculating ...") //> calculating ...
Thread.sleep() //> 3 + 3 = 6
}
这是一个标准的异步运算;在成功完成运算事件上绑定callback来获取在其它线程中的运算结果。我们也可以进行异常处理:
val fdz = Future { / } //> fdz : scala.concurrent.Future[Int] = List()
fdz.onFailure {
case e => println(s"error message {${e.getMessage}}")
}
Thread.sleep() //> 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() //> error message {/ by zero}
scala Future 实现了flatMap,我们可以把几个Future组合起来用:
def dbl(i: Int): Future[Int] = Future { Thread.sleep(); 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()
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() //> the combined result is: 42
scala Future利用flatMap实现了流程运算:先运算dbl再sqr再sum,这个顺序是固定的即使它们可能在不同的线程里运算,因为sqr依赖dbl的结果,而sum又依赖dbl和sqr的结果。
好了,既然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, .second) //> res0: Long = 1465907784714
Thread.sleep()
Await.result(fs, .second) //> res1: Long = 1465907784714
可以看到fs是在Future构建时即时运算的,而且只会运算一次。如果scala Future中包括了能产生副作用的代码,在构建时就会立即产生副作用。所以我们是无法使用scala Future来编写纯函数的,那么在scalaz里就必须为并发编程提供一个与scala Future具同等功能但又不会立即产生副作用的类型了,这就是scalaz版本的Future。我们看看scalaz是如何定义Future的:scalaz.concurrent/Future.scala
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]
...
Future[A]就是个Free Monad。它的结构化表达方式分别有Now,Async,Suspend,BindSuspend,BindAsync。我们可以用这些结构实现flatMap函数,所以Future就是Free Monad:
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>)
可以看到fnow是个即时运算的构建器,而这个now就是一个lift函数, 它负责把一个普通无副作用运算升格成Future。fdelay,fapply分别把运算存入trampoline进行结构化了。我们必须另外运算trampoline来运行结构内的运算:
fdelay.run //> run...
//| res0: Long = 1465910524847
Thread.sleep()
fdelay.run //> run...
//| res1: Long = 1465910525881
fapply.run //> run...
//| res2: Long = 1465910525883
Thread.sleep()
fapply.run //> run...
//| res3: Long = 1465910526884
scalaz Future只有在运算时才会产生副作用,而且可以多次运算。
我们可以用即时(blocking)、异步、定时方式来运算Future:
fapply.unsafePerformSync //> run...
//| res4: Long = 1465958049118
fapply.unsafePerformAsync {
case a => println(a)
}
Thread.sleep()
fapply.unsafePerformSyncFor( second) //> run...
//| 1465958051126
//| run...
//| res5: Long = 1465958052172
结构化状态Async代表了scalaz Future的多线程处理特性:
/**
* 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)
}
我们看到apply和schedule在构建Future时对运算线程进行了配置。
如果我们需要模仿scala Future的功效可以用unsafeStart:
val fs = fapply.unsafeStart //> run...
//| fs : scalaz.concurrent.Future[Long] = Suspend(<function0>)
fs.run //> res6: Long = 1465958922401
Thread.sleep()
fs.run //> res7: Long = 1465958922401
我们也可以用scala Future的callback方式用async函数把自定义的callback挂在构建的Future上:
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!!!
scala Future和scalaz Future之间可以相互转换:
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
}
突然发现scalaz Future是没有异常处理(exception)功能的。scalaz提供了concurrent.Task类型填补了Future的这部分缺陷。我们会在下篇讨论Task。
我们用上面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()
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() //> result c is:42
Scalaz(44)- concurrency :scalaz Future,尚不完整的多线程类型的更多相关文章
- Java多线程编程:Callable、Future和FutureTask浅析(多线程编程之四)
java多线程-概念&创建启动&中断&守护线程&优先级&线程状态(多线程编程之一)java多线程同步以及线程间通信详解&消费者生产者模式&死锁& ...
- Java Concurrency - Callable & Future
One of the advantages of the Executor framework is that you can run concurrent tasks that return a r ...
- 华为ENSP进行evn实验,尚不完整,但已经有RT1、RT2、RT3、RT4了
组网R1 -- CE12800 -- CE12800 --- R2 其中R1.R2是模拟VM的 R1的配置: interface GigabitEthernet0/0/0#interface Gig ...
- Scalaz(50)- scalaz-stream: 安全的无穷运算-running infinite stream freely
scalaz-stream支持无穷数据流(infinite stream),这本身是它强大的功能之一,试想有多少系统需要通过无穷运算才能得以实现.这是因为外界的输入是不可预料的,对于系统本身就是无穷的 ...
- Scalaz(47)- scalaz-stream: 深入了解-Source
scalaz-stream库的主要设计目标是实现函数式的I/O编程(functional I/O).这样用户就能使用功能单一的基础I/O函数组合成为功能完整的I/O程序.还有一个目标就是保证资源的安全 ...
- Scalaz(53)- scalaz-stream: 程序运算器-application scenario
从上面多篇的讨论中我们了解到scalaz-stream代表一串连续无穷的数据或者程序.对这个数据流的处理过程就是一个状态机器(state machine)的状态转变过程.这种模式与我们通常遇到的程序流 ...
- Scalaz(49)- scalaz-stream: 深入了解-Sink/Channel
一个完整的scalaz-stream有以下几个部分组成:Source -> Transducer -> Sink,用直白文字来描述就是:“输入 -> 传换 -> 输出”.我们已 ...
- Scalaz(41)- Free :IO Monad-Free特定版本的FP语法
我们不断地重申FP强调代码无副作用,这样才能实现编程纯代码.像通过键盘显示器进行交流.读写文件.数据库等这些IO操作都会产生副作用.那么我们是不是为了实现纯代码而放弃IO操作呢?没有IO的程序就是一段 ...
- Scalaz(40)- Free :versioned up,再回顾
在上一篇讨论里我在设计示范例子时遇到了一些麻烦.由于Free Monad可能是一种主流的FP编程规范,所以在进入实质编程之前必须把所有东西都搞清楚.前面遇到的问题主要与scalaz Free的Free ...
随机推荐
- css自适应宽高等腰梯形
t1是梯形, ct是梯形里面的内容. 梯形的高度会随着内容的高度撑高.宽度随着浏览器窗口变宽. 梯形上窄下宽或上宽下窄可以通过 transform 的大小来修改. <div class=&quo ...
- Mongodb 的基本使用
一.cmd连接mongodb 服务 进入mongodb的bin目录下:[D:\mongodb3.2.5\bin]$ mongo 127.0.0.1:27017 常用查询: show dbs 查看所有数 ...
- img list
- Python之文件读写
本节内容: I/O操作概述 文件读写实现原理与操作步骤 文件打开模式 Python文件操作步骤示例 Python文件读取相关方法 文件读写与字符编码 一.I/O操作概述 I/O在计算机中是指Input ...
- 设置让TortoiseGit记住账号和密码
方法一:在"C:\Documents and Settings\Administrator\.gitconfig" 文件 或 "项目/.git/config"文 ...
- 使用office生成PDF文件
网络上有很多word转pdf的软件,功能效果不尽相同,对于想要把word转换成pdf格式的网友来说,一款实用强大的工具是必不可少的,踏破铁鞋无觅处,原来office2010就有符合你要求的功能.PDF ...
- DA - 信息获取途径汇总
目的驱动 大多数情况下,都是为了解决某个问题或完成某项任务,才需要进行针对性的.大范围的.细致化的信息获取. 那么,信息获取的方式和来源,就应该紧紧围绕这个"问题和任务"本身来确定 ...
- Canvas 示例:4种超炫的网站动画背景效果
今天,我们想分享一些动画背景的灵感.全屏背景图片的网站头部是最新的网页设计趋势,已经持续了一段时间.最近人们一直在转向动画添加更多的视觉兴趣到他们的网站中,在这里我们想向您分享几个使用 JavaSc ...
- 材价看板(2)- 运行两周的kanban,改进的起点
改进从何谈起?必须找到起点,那起点从哪来? 看板不需要像Scrum那样改变以往工作角色,简单通过任务上墙,配合敏捷的设计就能通过显示化日常工作来让问题自己蹦出来.在任何一个新采用看板的研发团队,执行一 ...
- js的日期格式化
function date(){ var date = new Date(); var year = date.getFullYear(); var month = date.getMonth()+1 ...