Future 和 Promise 教程
概述
在现代编程中,异步编程是一个非常重要的概念。Scala 提供了 Future 和 Promise 来帮助我们处理异步操作。Future 表示一个可能在未来完成的计算结果,而 Promise 则是一个可以控制 Future 结果的容器。
1. Future 简介
1.1 什么是 Future?
Future 是一个表示异步计算结果的容器。它代表一个可能在未来某个时间点完成的计算。Future 可以处于以下几种状态:
- Pending: 计算尚未完成。
- Completed: 计算已经完成,结果可能是成功或失败。
1.2 Future 的基本用法
在 Scala 中,Future 通常通过 Future 伴生对象的 apply 方法创建。以下是一个简单的例子:
import scala.concurrent.{Future, Await}
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
object FutureExample extends App {
val futureResult: Future[Int] = Future {
Thread.sleep(1000) // 模拟耗时操作
42
}
val result: Int = Await.result(futureResult, 2.seconds)
println(s"Future result: $result")
}
在这个例子中,我们创建了一个 Future,它会在 1 秒后返回结果 42。我们使用 Await.result 来等待 Future 完成并获取结果。
1.3 Future 的回调函数
除了使用 Await,我们还可以使用回调函数来处理 Future 的结果。常用的回调函数包括 onComplete、onSuccess 和 onFailure。
futureResult.onComplete {
case scala.util.Success(value) => println(s"Success: $value")
case scala.util.Failure(ex) => println(s"Failure: ${ex.getMessage}")
}
2. Promise 简介
2.1 什么是 Promise?
Promise 是一个可以控制 Future 结果的容器。通过 Promise,我们可以手动设置 Future 的结果,无论是成功还是失败。
2.2 Promise 的基本用法
以下是一个使用 Promise 的简单例子:
import scala.concurrent.{Future, Promise}
import scala.concurrent.ExecutionContext.Implicits.global
object PromiseExample extends App {
val promise: Promise[Int] = Promise[Int]()
val future: Future[Int] = promise.future
future.onComplete {
case scala.util.Success(value) => println(s"Success: $value")
case scala.util.Failure(ex) => println(s"Failure: ${ex.getMessage}")
}
// 模拟异步操作
Future {
Thread.sleep(1000)
promise.success(42)
}
}
在这个例子中,我们创建了一个 Promise,并通过 promise.success 手动设置 Future 的结果为 42。
3. Future 和 Promise 的组合
3.1 组合多个 Future
在实际应用中,我们经常需要组合多个 Future。Scala 提供了多种方法来组合 Future,例如 map、flatMap、zip 等。
val future1: Future[Int] = Future { 1 }
val future2: Future[Int] = Future { 2 }
val combinedFuture: Future[(Int, Int)] = future1.zip(future2)
combinedFuture.onComplete {
case scala.util.Success((value1, value2)) => println(s"Combined result: ($value1, $value2)")
case scala.util.Failure(ex) => println(s"Failure: ${ex.getMessage}")
}
3.2 使用 Promise 控制多个 Future
我们也可以使用 Promise 来控制多个 Future 的结果。例如,我们可以创建一个 Promise,并在多个 Future 完成后设置其结果。
val promise: Promise[Int] = Promise[Int]()
val future1: Future[Int] = Future { 1 }
val future2: Future[Int] = Future { 2 }
Future.sequence(List(future1, future2)).onComplete {
case scala.util.Success(values) => promise.success(values.sum)
case scala.util.Failure(ex) => promise.failure(ex)
}
promise.future.onComplete {
case scala.util.Success(value) => println(s"Sum of results: $value")
case scala.util.Failure(ex) => println(s"Failure: ${ex.getMessage}")
}
4. 实践练习
4.1 练习 1: 使用 Future 计算斐波那契数列
编写一个程序,使用 Future 计算斐波那契数列的前 10 个数字,并打印结果。
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
object FibonacciFuture extends App {
def fibonacci(n: Int): Future[Int] = Future {
if (n <= 1) n
else fibonacci(n - 1).flatMap(a => fibonacci(n - 2).map(b => a + b))
}
val fibonacciNumbers: List[Future[Int]] = (0 to 9).map(fibonacci).toList
Future.sequence(fibonacciNumbers).onComplete {
case scala.util.Success(values) => println(s"Fibonacci numbers: $values")
case scala.util.Failure(ex) => println(s"Failure: ${ex.getMessage}")
}
}
4.2 练习 2: 使用 Promise 实现超时机制
编写一个程序,使用 Promise 实现一个超时机制。如果 Future 在指定时间内没有完成,则返回一个失败的结果。
import scala.concurrent.{Future, Promise}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
object TimeoutPromise extends App {
def timeout[T](future: Future[T], duration: FiniteDuration): Future[T] = {
val promise: Promise[T] = Promise[T]()
future.onComplete(promise.tryComplete)
Future {
Thread.sleep(duration.toMillis)
promise.tryFailure(new Exception("Timeout"))
}
promise.future
}
val future: Future[Int] = Future {
Thread.sleep(2000)
42
}
timeout(future, 1.second).onComplete {
case scala.util.Success(value) => println(s"Success: $value")
case scala.util.Failure(ex) => println(s"Failure: ${ex.getMessage}")
}
}
5. 总结
Future 和 Promise 是 Scala 中处理异步编程的重要工具。通过 Future,我们可以表示一个可能在未来完成的计算结果;通过 Promise,我们可以手动控制 Future 的结果。掌握这两个概念对于编写高效、可维护的异步代码至关重要。
希望这篇教程能帮助你更好地理解 Future 和 Promise,并在实际编程中灵活运用它们。