1. 程式人生 > >scala-Future和Promise

scala-Future和Promise

ext main similar method led for gre 延遲 使用

首先說明同步與異步,阻塞與非阻塞的問題:
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中的FuturePromise都是非阻塞的執行,既可以通過回調函數獲取結果,但是也可以通過阻塞的方法串行獲取結果。

Future

一個Future會持有一個值,雖然這個值在將來某個時間點才可用。

  1. 如果計算未完成,那麽這個Future就未完成。
  2. 如果計算完成(得到結果或者異常),這個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