scala-Future和Promise
首先說明同步與異步,阻塞與非阻塞的問題:
Asynchronous vs. Synchronous
A method call is considered synchronous if the caller cannot make progress until the method returns a value or throws an exception. On the other hand, an asynchronous call allows the caller to progress after a finite number of steps, and the completion of the method may be signalled via some additional mechanism (it might be a registered callback, a Future, or a message).
A synchronous API may use blocking to implement synchrony, but this is not a necessity. A very CPU intensive task might give a similar behavior as blocking. In general, it is preferred to use asynchronous APIs, as they guarantee that the system is able to progress.
Non-blocking vs. Blocking
We talk about blocking if the delay of one thread can indefinitely delay some of the other threads. A good example is a resource which can be used exclusively by one thread using mutual exclusion. If a thread holds on to the resource indefinitely (for example accidentally running an infinite loop) other threads waiting on the resource can not progress. In contrast, non-blocking means that no thread is able to indefinitely delay others.
Non-blocking operations are preferred to blocking ones, as the overall progress of the system is not trivially guaranteed when it contains blocking operations.
以上文獻摘自akka文檔,一個方法之所以被稱為同步方法,是因為直到該方法返回某值或者拋出異常,該方法的調用者才能得到結果(make progress
)。如果一個異步調用需要通過額外的機制(比如callback
,Future
,message
)。如果一個線程的延遲導致了另一個(一些)線程的延遲,那麽久出現了阻塞(blocking
)。一個例子就是一個資源被一個線程所獨占,那麽其他線程需要等待這個線程釋放資源才能繼續執行。
scala中的Future
和Promise
都是非阻塞的執行,既可以通過回調函數獲取結果,但是也可以通過阻塞的方法串行獲取結果。
Future
一個Future
會持有一個值,雖然這個值在將來某個時間點才可用。
- 如果計算未完成,那麽這個
Future
就未完成。 - 如果計算完成(得到結果或者異常),這個
Future
就完成了。
Future
只能被指派一次,一旦Future
給定了一個值或異常,它的結果不能修改。
object Main extends App {
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
val f:Future[Int]=Future{
Thread.sleep(100)//模擬某個耗時操作 比如網絡請求
println("haha")
10
}
Thread.sleep(1000)
}
//haha
異步方法獲取結果
目的獲取結果,而不是控制執行過程。
scala提供了onSuccess
等回調函數。其簽名為:def onComplete[U](f: Try[T] => U)(implicit executor: ExecutionContext): Unit
f.onComplete({
case Success(i) => println(i)
case Failure(e) => e.printStackTrace()
})
以上代碼采用偏函數形式,或者:
f.onComplete(result=>result match {
case Success(i)=>println(i)
case Failure(e)=>e.printStackTrace()
})
還可以註冊多個回調:
f.onComplete(result=>result match {
case Success(i)=>println(i)
})
f.onComplete(result=>result match {
case Success(i)=>println(i+20)
})
註:多個回調函數之間並不保證執行順序。
同步方法獲取結果
通過Await.result
可以同步獲取結果,或者超時或者異常。Await.ready
等待計算完成,不返回結果。
val r=Await.result(f,Duration.Inf) //Await.result(f,1 seconds)
Promise
除了通過Future.apply
創建Future
對象,還可以使用Promise.future
。如果說Future
是一個只讀的,值還沒計算的占位符。那麽Promise
就是一個可寫的,單次指派的容器。Promise
可以通過調用success
代表Future
成功完成,failure
方法拋出異常。或者更抽象的complete
。
object Main extends App {
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{Future,Promise}
// import scala.concurrent.duration._
val p=Promise[Int]
val f=p.future
val producer=Future{
p complete Try{
100
}
}
val consumer=Future{
f onComplete{
case Success(i)=>println(i)
case Failure(e)=>e.printStackTrace()
}
}
Thread.sleep(1000)
}
scala-Future和Promise