1. 程式人生 > >Scala 非同步程式設計之 Future

Scala 非同步程式設計之 Future

同步非同步,阻塞非阻塞,在IO模型中幾個概念組合在一起不是很容易理解,但是隻從程式碼執行的角度看同步非同步是很清晰的:

同步代表這段程式碼中的邏輯必須執行完畢,而非同步代表呼叫馬上返回,但通常情況下是獲取不到需要的值。

同步:val  value={

Thread.sleep(2000)

1

}

非同步: val value=Future{

Thread.sleep(2000)

1

在scala repl執行上面程式碼可以發現同步等待兩秒後返回結果 Int 1,而非同步馬上返回了

value: scala.concurrent.Future[Int] = List()。

注意:在shell中必須匯入 (1)import scala.concurrent.Future 以及 (2) import scala.concurrent.ExecutionContext.Implicits.global

匯入(1)是因為需要使用Future,(實際上使用了Future.apply方法),匯入(2)則是由非同步程式設計的內在邏輯決定的。

同步方法中的邏輯是由main主執行緒逐步執行的,而非同步程式設計的思路是:

在執行Future.apply{非同步程式碼塊}時,主執行緒將非同步程式碼塊交給新的執行緒,新起的執行緒負責非同步程式碼塊的計算,而主執行緒則解放出來,執行下一步。

在scala的Future中,apply方法如下:

def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] 

我們匯入(2) import scala.concurrent.ExecutionContext.Implicits.global,實際上這是scala提供的預設的work-stealing thread pool,我們也可以explicitly地申明:

import scala.concurrent.ExecutionContext

implicit lazy val workStealingPoolExecutionContext: ExecutionContext = {  
    val workStealingPool :ExecutorService = Executors.newWorkStealingPool
    ExecutionContext.fromExecutor(workStealingPool)
}

將implicit 的 ExecutionContext  傳給了Future中的(implicit executor: ExecutionContext),使用lazy是為了節約資源,即使我們實現了ExecutionContext ,但實際上不會馬上申請執行緒佔用資源,只有真正呼叫Future方法時,才會執行lazy後面的程式碼。

在獲取future值得時候,我們可以用阻塞的方式,也可以使用回撥。

阻塞:

import scala.concurrent.duration._
import scala.concurrent.Await
val resultValue= Await.result(value, 2 seconds)

result的方法如下

   def result[T](awaitable: Awaitable[T], atMost: Duration): T =
      blocking(awaitable.result(atMost)(AwaitPermission))
  }

傳入最大等待時長,在這期間阻塞獲取future的值,超時後報錯,通常用於測試用例。

回撥:

value onComplete {  
case Success(intValue) =>  println("success:   "+intValue)  
case Failure(error) => println("An error has occured: " + error.getMessage)  
}  

可以通過模式匹配的方式獲取值。