6Scala for the Impatient(第2版)

并发

Scala并发

FuturePromiseActor模型Akka基础

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第6章:并发

一、导读

1.1 本章学习目标

第6章讲解 Scala 的并发编程:Future、Promise、Actor 模型。

本章核心学习目标:

  • 掌握 Future:异步计算
  • 理解 Promise:手动完成 Future
  • 了解 Actor 模型:Akka 基础

1.2 为什么本章如此重要

并发是现代编程的核心挑战。Scala 提供了多种并发模型,Future 是最常用的。

1.3 核心问题引导

Future 如何避免回调地狱?

Promise 和 Future 的关系是什么?

Actor 模型比线程有什么优势?


二、核心概念详解

6.1 Future

scala
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global

// 创建 Future
val future = Future {
    Thread.sleep(1000)
    42
}

// 回调
future.onComplete {
    case Success(value) => println(s"Got: $value")
    case Failure(ex) => println(s"Error: ${ex.getMessage}")
}

// 转换
val doubled = future.map(_ * 2)
val filtered = future.filter(_ > 10)
val recovered = future.recover { case _ => 0 }

// 组合
val f1 = Future(1)
val f2 = Future(2)

// for 推导式
val result = for {
    a <- f1
    b <- f2
} yield a + b

// 或 zip
val zipped = f1.zip(f2).map { case (a, b) => a + b }

// 等待结果 (测试用)
val value = Await.result(future, 5.seconds)

6.2 Promise

scala
// Promise: 手动完成 Future
val promise = Promise[Int]()
val future = promise.future

// 在另一个线程中完成
Future {
    Thread.sleep(1000)
    promise.success(42)
}

// 完成方式
// promise.success(value)
// promise.failure(exception)
// promise.trySuccess(value)  // 不抛异常
// promise.tryFailure(ex)

6.3 Actor 模型 (Akka)

scala
import akka.actor._

// 定义消息
case class Greet(name: String)
case class Reply(message: String)

// 定义 Actor
class Greeter extends Actor {
    def receive = {
        case Greet(name) =>
            println(s"Hello, $name!")
            sender() ! Reply(s"Hello, $name!")
        case msg =>
            println(s"Unknown message: $msg")
    }
}

// 创建和使用
val system = ActorSystem("MySystem")
val greeter = system.actorOf(Props[Greeter], "greeter")

greeter ! Greet("Alice")
greeter ! Greet("Bob")

// system.terminate()

三、实战案例

3.1 案例一:并发 HTTP 请求

scala
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global

def fetchUrl(url: String): Future[String] = Future {
    // 模拟 HTTP 请求
    Thread.sleep(scala.util.Random.nextInt(1000))
    s"Response from $url"
}

val urls = List(
    "https://api1.example.com",
    "https://api2.example.com",
    "https://api3.example.com"
)

// 并发执行所有请求
val futures = urls.map(fetchUrl)
val allResults = Future.sequence(futures)

// 等待所有完成
val results = Await.result(allResults, 10.seconds)
results.foreach(println)

// 带超时的版本
val withTimeout = Future.firstCompletedOf(
    futures :+ Future.failed(new TimeoutException("Timeout"))
)

四、本章小结

Future 表示异步计算的结果

Promise 手动完成 Future

Actor 模型提供消息传递的并发范式


五、思考与练习

Future 的 ExecutionContext 是什么?

Actor 模型如何避免死锁?


6/7并发
0%