Scala教程之:Future和Promise(一)

简介: Scala教程之:Future和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 operation
  println("checking donut stock")
  10
}


注意这里需要引入scala.concurrent.ExecutionContext.Implicits.global, 它会提供一个默认的线程池来异步执行Future。


阻塞方式获取Future的值


println("\nStep 2: Call method which returns a Future")
  import scala.concurrent.Await
  import 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可以提供默认值。看下下面的例子:


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)
相关文章
|
4月前
|
存储 前端开发 安全
C++一分钟之-未来与承诺:std::future与std::promise
【6月更文挑战第27天】`std::future`和`std::promise`是C++异步编程的关键工具,用于处理未完成任务的结果。`future`代表异步任务的结果容器,可阻塞等待或检查结果是否就绪;`promise`用于设置`future`的值,允许多线程间通信。常见问题包括异常安全、多重获取、线程同步和未检查状态。解决办法涉及智能指针管理、明确获取时机、确保线程安全以及检查未来状态。示例展示了使用`std::async`和`future`执行异步任务并获取结果。
66 2
|
12天前
|
消息中间件 存储 前端开发
「3.4w字」超保姆级教程带你实现Promise的核心功能
该文章通过详细的步骤和示例代码,逐步介绍了如何从零开始实现一个符合ECMAScript标准的Promise对象,涵盖了Promise的基本使用、状态管理、链式调用、错误处理机制及Promise.all和Promise.resolve等方法的实现。
「3.4w字」超保姆级教程带你实现Promise的核心功能
|
5月前
|
前端开发 Go
Golang深入浅出之-Go语言中的异步编程与Future/Promise模式
【5月更文挑战第3天】Go语言通过goroutines和channels实现异步编程,虽无内置Future/Promise,但可借助其特性模拟。本文探讨了如何使用channel实现Future模式,提供了异步获取URL内容长度的示例,并警示了Channel泄漏、错误处理和并发控制等常见问题。为避免这些问题,建议显式关闭channel、使用context.Context、并发控制机制及有效传播错误。理解并应用这些技巧能提升Go语言异步编程的效率和健壮性。
255 5
Golang深入浅出之-Go语言中的异步编程与Future/Promise模式
|
5月前
|
存储 前端开发 安全
【C++并发编程】std::future、std::async、std::packaged_task与std::promise的深度探索(三)
【C++并发编程】std::future、std::async、std::packaged_task与std::promise的深度探索
65 0
|
5月前
|
存储 设计模式 前端开发
【C++并发编程】std::future、std::async、std::packaged_task与std::promise的深度探索(二)
【C++并发编程】std::future、std::async、std::packaged_task与std::promise的深度探索
90 0
|
5月前
|
并行计算 前端开发 安全
【C++并发编程】std::future、std::async、std::packaged_task与std::promise的深度探索(一)
【C++并发编程】std::future、std::async、std::packaged_task与std::promise的深度探索
151 0
|
5月前
|
前端开发 C++
C++11实用技术(三)std::future、std::promise、std::packaged_task、async
C++11实用技术(三)std::future、std::promise、std::packaged_task、async
79 0
|
12月前
|
存储 移动开发 JavaScript
带你读《现代Javascript高级教程》二十六、JS中的异步编程与Promise(1)
带你读《现代Javascript高级教程》二十六、JS中的异步编程与Promise(1)
|
12月前
|
前端开发 JavaScript
带你读《现代Javascript高级教程》二十六、JS中的异步编程与Promise(2)
带你读《现代Javascript高级教程》二十六、JS中的异步编程与Promise(2)
|
12月前
|
存储 前端开发 JavaScript
带你读《现代Javascript高级教程》二十七、实现符合Promise/A+规范的Promise(1)
带你读《现代Javascript高级教程》二十七、实现符合Promise/A+规范的Promise(1)