日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Scala教程之:Future和Promise

發布時間:2024/2/28 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Scala教程之:Future和Promise 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 定義返回Future的方法
    • 阻塞方式獲取Future的值
    • 非阻塞方式獲取Future的值
    • Future鏈
    • flatmap VS map
    • Future.sequence() VS Future.traverse()
    • Future.foldLeft VS Future reduceLeft
    • Future firstCompletedOf
    • Future zip VS zipWith
    • Future andThen
    • 自定義threadpool
    • recover() recoverWith() and fallbackTo()
    • promise

在scala中可以方便的實現異步操作,這里是通過Future來實現的,和java中的Future很相似,但是功能更加強大。

定義返回Future的方法

下面我們看下如何定義一個返回Future的方法:

println("Step 1: Define a method which returns a Future") import scala.concurrent.Future import scala.concurrent.ExecutionContext.Implicits.global def donutStock(donut: String): Future[Int] = Future {// assume some long running database operationprintln("checking donut stock")10 }

注意這里需要引入scala.concurrent.ExecutionContext.Implicits.global, 它會提供一個默認的線程池來異步執行Future。

阻塞方式獲取Future的值

println("\nStep 2: Call method which returns a Future")import scala.concurrent.Awaitimport scala.concurrent.duration._val vanillaDonutStock = Await.result(donutStock("vanilla donut"), 5 seconds)println(s"Stock of vanilla donut = $vanillaDonutStock")

donutStock() 是異步執行的,我們可以使用Await.result() 來阻塞主線程來等待donutStock()的執行結果。

下面是其輸出:

Step 2: Call method which returns a Future checking donut stock Stock of vanilla donut = 10

非阻塞方式獲取Future的值

我們可以使用Future.onComplete() 回調來實現非阻塞的通知:

println("\nStep 2: Non blocking future result") import scala.util.{Failure, Success} donutStock("vanilla donut").onComplete {case Success(stock) => println(s"Stock for vanilla donut = $stock")case Failure(e) => println(s"Failed to find vanilla donut stock, exception = $e") } Thread.sleep(3000)

Future.onComplete() 有兩種可能情況,Success 或者 Failure,需要引入: import scala.util.{Failure, Success}。

Future鏈

有時候我們需要在獲得一個Future之后再繼續對其進行操作,有點類似于java中的管道,下面看一個例子:

println("\nStep 2: Define another method which returns a Future") def buyDonuts(quantity: Int): Future[Boolean] = Future {println(s"buying $quantity donuts")true }

上面我們又定義了一個方法,用來接收donutStock()的返回值,然后再返回一個Future[Boolean] 。

我們看下使用flatmap該怎么鏈接他們:

println("\nStep 3: Chaining Futures using flatMap") val buyingDonuts: Future[Boolean] = donutStock("plain donut").flatMap(qty => buyDonuts(qty)) import scala.concurrent.Await import scala.concurrent.duration._ val isSuccess = Await.result(buyingDonuts, 5 seconds) println(s"Buying vanilla donut was successful = $isSuccess")

同樣的,我們還可以使用for語句來進行鏈接:

println("\nStep 3: Chaining Futures using for comprehension") for {stock <- donutStock("vanilla donut")isSuccess <- buyDonuts(stock) } yield println(s"Buying vanilla donut was successful = $isSuccess")Thread.sleep(3000)

flatmap VS map

map就是對集合中的元素進行重映射,而flatmap則會將返回的值拆散然后重新組合。 下面舉個直觀的例子:

val buyingDonuts: Future[Boolean] = donutStock("plain donut").flatMap(qty => buyDonuts(qty))

flatMap返回的值是Future[Boolean]。

val buyingDonuts: Future[Future[Boolean]] = donutStock("plain donut").Map(qty => buyDonuts(qty))

map返回的值是Future[Future[Boolean]]。

Future.sequence() VS Future.traverse()

如果我們有很多個Future,然后想讓他們并行執行,則可以使用 Future.sequence() 。

println(s"\nStep 2: Create a List of future operations") val futureOperations = List(donutStock("vanilla donut"),donutStock("plain donut"),donutStock("chocolate donut") )println(s"\nStep 5: Call Future.sequence to run the future operations in parallel") val futureSequenceResults = Future.sequence(futureOperations) futureSequenceResults.onComplete {case Success(results) => println(s"Results $results")case Failure(e) => println(s"Error processing future operations, error = ${e.getMessage}") }

Future.traverse() 和Future.sequence() 類似, 唯一不同的是,Future.traverse()可以對要執行的Future進行操作,如下所示:

println(s"\nStep 3: Call Future.traverse to convert all Option of Int into Int") val futureTraverseResult = Future.traverse(futureOperations){ futureSomeQty =>futureSomeQty.map(someQty => someQty.getOrElse(0)) } futureTraverseResult.onComplete {case Success(results) => println(s"Results $results")case Failure(e) => println(s"Error processing future operations, error = ${e.getMessage}") }

Future.foldLeft VS Future reduceLeft

foldLeft 和 reduceLeft 都是用來從左到右做集合操作的,區別在于foldLeft可以提供默認值??聪孪旅娴睦?#xff1a;

println(s"\nStep 3: Call Future.foldLeft to fold over futures results from left to right") val futureFoldLeft = Future.foldLeft(futureOperations)(0){ case (acc, someQty) =>acc + someQty.getOrElse(0) } futureFoldLeft.onComplete {case Success(results) => println(s"Results $results")case Failure(e) => println(s"Error processing future operations, error = ${e.getMessage}") }

輸出結果:

Step 3: Call Future.foldLeft to fold over futures results from left to right Results 20 println(s"\nStep 3: Call Future.reduceLeft to fold over futures results from left to right") val futureFoldLeft = Future.reduceLeft(futureOperations){ case (acc, someQty) =>acc.map(qty => qty + someQty.getOrElse(0)) } futureFoldLeft.onComplete {case Success(results) => println(s"Results $results")case Failure(e) => println(s"Error processing future operations, error = ${e.getMessage}") }

輸出結果:

Step 3: Call Future.reduceLeft to fold over futures results from left to right Results Some(20)

Future firstCompletedOf

firstCompletedOf在處理多個Future請求時,會返回第一個處理完成的future結果。

println(s"\nStep 3: Call Future.firstCompletedOf to get the results of the first future that completes") val futureFirstCompletedResult = Future.firstCompletedOf(futureOperations) futureFirstCompletedResult.onComplete {case Success(results) => println(s"Results $results")case Failure(e) => println(s"Error processing future operations, error = ${e.getMessage}") }

Future zip VS zipWith

zip用來將兩個future結果組合成一個tuple. zipWith則可以自定義Function來處理future返回的結果。

println(s"\nStep 3: Zip the values of the first future with the second future") val donutStockAndPriceOperation = donutStock("vanilla donut") zip donutPrice() donutStockAndPriceOperation.onComplete {case Success(results) => println(s"Results $results")case Failure(e) => println(s"Error processing future operations, error = ${e.getMessage}") }

輸出值:

Step 3: Zip the values of the first future with the second future checking donut stock Results (Some(10),3.25)

使用zipwith的例子:

println(s"\nStep 4: Call Future.zipWith and pass-through function qtyAndPriceF") val donutAndPriceOperation = donutStock("vanilla donut").zipWith(donutPrice())(qtyAndPriceF) donutAndPriceOperation.onComplete {case Success(result) => println(s"Result $result")case Failure(e) => println(s"Error processing future operations, error = ${e.getMessage}") }

輸出結果:

Step 4: Call Future.zipWith and pass-through function qtyAndPriceF checking donut stock Result (10,3.25)

Future andThen

andThen后面可以跟一個自定義的PartialFunction,來處理Future返回的結果, 如下所示:

println(s"\nStep 2: Call Future.andThen with a PartialFunction") val donutStockOperation = donutStock("vanilla donut") donutStockOperation.andThen { case stockQty => println(s"Donut stock qty = $stockQty")}

輸出結果:

Step 2: Call Future.andThen with a PartialFunction checking donut stock Donut stock qty = Success(10)

自定義threadpool

上面的例子中, 我們都是使用了scala的全局ExecutionContext: scala.concurrent.ExecutionContext.Implicits.global.
同樣的,我們也可以自定義你自己的ExecutionContext。下面是一個使用java.util.concurrent.Executors的例子:

println("Step 1: Define an ExecutionContext")val executor = Executors.newSingleThreadExecutor()implicit val ec = scala.concurrent.ExecutionContext.fromExecutor(executor)println("\nStep 2: Define a method which returns a Future")import scala.concurrent.Futuredef donutStock(donut: String): Future[Int] = Future {// assume some long running database operationprintln("checking donut stock")10}println("\nStep 3: Call method which returns a Future")val donutStockOperation = donutStock("vanilla donut")donutStockOperation.onComplete {case Success(donutStock) => println(s"Results $donutStock")case Failure(e) => println(s"Error processing future operations, error = ${e.getMessage}")}Thread.sleep(3000)executor.shutdownNow()

recover() recoverWith() and fallbackTo()

這三個方法主要用來處理異常的,recover是用來從你已知的異常中恢復,如下所示:

println("\nStep 3: Call Future.recover to recover from a known exception") donutStock("unknown donut").recover { case e: IllegalStateException if e.getMessage == "Out of stock" => 0 }.onComplete {case Success(donutStock) => println(s"Results $donutStock")case Failure(e) => println(s"Error processing future operations, error = ${e.getMessage}") }

recoverWith()和recover()類似,不同的是他的返回值是一個Future。

println("\nStep 3: Call Future.recoverWith to recover from a known exception") donutStock("unknown donut").recoverWith { case e: IllegalStateException if e.getMessage == "Out of stock" => Future.successful(0) }.onComplete {case Success(donutStock) => println(s"Results $donutStock")case Failure(e) => println(s"Error processing future operations, error = ${e.getMessage}") }

fallbackTo()是在發生異常時,去調用指定的方法:

println("\nStep 3: Call Future.fallbackTo") val donutStockOperation = donutStock("plain donut").fallbackTo(similarDonutStock("vanilla donut")).onComplete {case Success(donutStock) => println(s"Results $donutStock")case Failure(e) => println(s"Error processing future operations, error = ${e.getMessage}") }

promise

熟悉ES6的同學可能知道,promise是JS在ES6中引入的新特性,其主要目的是將回調轉變成鏈式調動。

當然scala的promise和ES6的promise還是不一樣的,我們看下scala中promise是怎么用的:

println("Step 1: Define a method which returns a Future")import scala.concurrent.ExecutionContext.Implicits.globaldef donutStock(donut: String): Int = {if(donut == "vanilla donut") 10else throw new IllegalStateException("Out of stock")}println(s"\nStep 2: Define a Promise of type Int")val donutStockPromise = Promise[Int]()println("\nStep 3: Define a future from Promise")val donutStockFuture = donutStockPromise.futuredonutStockFuture.onComplete {case Success(stock) => println(s"Stock for vanilla donut = $stock")case Failure(e) => println(s"Failed to find vanilla donut stock, exception = $e")}println("\nStep 4: Use Promise.success or Promise.failure to control execution of your future")val donut = "vanilla donut"if(donut == "vanilla donut") {donutStockPromise.success(donutStock(donut))} else {donutStockPromise.failure(Try(donutStock(donut)).failed.get)}println("\nStep 5: Completing Promise using Promise.complete() method")val donutStockPromise2 = Promise[Int]()val donutStockFuture2 = donutStockPromise2.futuredonutStockFuture2.onComplete {case Success(stock) => println(s"Stock for vanilla donut = $stock")case Failure(e) => println(s"Failed to find vanilla donut stock, exception = $e")}donutStockPromise2.complete(Try(donutStock("unknown donut")))

上面例子中我們使用了 Promise.success, Promise.failure, Promise.complete() 來控制程序的運行。

更多精彩內容且看:

  • 區塊鏈從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特幣等持續更新
  • Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新
  • Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新
  • java程序員從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程

更多教程請參考 flydean的博客

超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

總結

以上是生活随笔為你收集整理的Scala教程之:Future和Promise的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。