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)
}
可以通過模式匹配的方式獲取值。