Scala语言拥有很强的表达能力,语法简洁,很接近人类的思考方式。利用map、flatMap方法作数据转换时,层层递进的演算方式,很像是在画流程图,中间没有停顿,思绪很流畅,不会被无关的变量声明、初始化等杂事打断。Scala中的Future可让你很是灵活的使用线程,而不须要关注底层的线程管理问题,Scala已经为你处理好一切。下面咱们以一个示例来讲明,将Future、map和flatMap组合起来会产生多大的威力!
数据库
假设咱们是一个VPS服务器提供商,如今考虑用户购买了VPS以后,要在控制台上执行建立磁盘快照的操做。系统须要执行的步骤以下:
服务器
1)根据用户id和VPS id,到数据库中分别取出相应记录并发
2)检查用户和VPS的状态,若是状态异常,返回报错信息异步
3)向消息队列发送一条建立磁盘快照的消息,若是消息发送失败,返回报错信息async
4)执行过程当中,若是有异常抛出,直接返回错误页面高并发
若是只有上面这四条需求,你是否是以为也太简单了!好吧,下面重头戏来了,为了保证系统的高并发,咱们还有第五条要求,ui
5)全部的操做都要异步执行,不能阻塞当前处理请求的线程spa
小伙伴们,如何实现,你想好了吗?线程
既要异步执行,又要优雅地处理跨线程异常,看看Scala是如何处理的吧!scala
def doDiskSnapshot(uid: String, vpsId: String) = Action.async { implicit request => { for { Some(user) <- getCollection("user").find(Json.obj("_id" -> uid)).one[User] Some(vps) <- getCollection("vps").find(Json.obj("_id" -> vpsId)).one[Vps] } yield { if(!user.disabled && !vps.disabled){ true } else { false } } }.flatMap{ isValid => if(isValid){ getCollection("snapshot-task").insert(SnapshotTask(...)).map{ wr => if(wr.ok && wr.n == 1){ Ok("操做成功!") } else { Ok("操做失败!") } } } else { Future(Ok("很抱歉,您的操做已被系统拒绝!")) } }.recover{ case t => Ok("很抱歉,发生系统错误,请稍候重试!") } }
第3-4行:从数据库中取出用户和VPS记录
第6行: 返回状态检查结果
第8行: 数据传递
第9行: 检查状态信息
第10行: 发送消息
第20行: 错误处理
整个执行过程一鼓作气,去掉方法声明一共22行代码,没有任何拖沓冗余的地方,让人不得不感叹Scala设计之精妙!
好了,文章到此结束。感兴趣的同窗能够猜猜看:假设线程池足够大,上面的代码一共用到了几个线程?答案会在后面公布。