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設計之精妙!
好了,文章到此結束。感興趣的同窗能夠猜猜看:假設線程池足夠大,上面的代碼一共用到了幾個線程?答案會在後面公佈。