Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
  • 第三部分:函数式编程与并发

第三部分:函数式编程与并发

第 13 章:协程进阶

13.1 协程的取消与异常处理

1. 协程的取消

在 Kotlin 协程中,取消(Cancellation)是一种协作机制,用于优雅地终止正在运行的协程。以下是关键点:

  • 取消协程的方式
    通过调用 Job.cancel() 方法取消协程:

    val job = launch {
        repeat(1000) { i ->
            println("Job: I'm sleeping $i...")
            delay(500L)
        }
    }
    delay(1300L)
    job.cancel() // 取消协程
    
  • 检查协程是否活跃
    协程内部需通过 isActive 或 ensureActive() 检查取消状态:

    launch {
        while (isActive) { // 检查协程是否被取消
            println("Working...")
            delay(100)
        }
    }
    
  • 释放资源
    使用 try {...} finally {...} 或 suspendCancellableCoroutine 确保资源释放:

    job.cancel()
    job.join() // 等待协程完成取消
    

2. 异常处理

协程中的异常传播遵循结构化并发规则,需通过 CoroutineExceptionHandler 或 try-catch 捕获。

  • 异常传播机制

    • 子协程异常会取消父协程及同级协程(除非使用 SupervisorJob)。
    • 通过 CoroutineExceptionHandler 全局捕获异常:
      val handler = CoroutineExceptionHandler { _, exception ->
          println("Caught $exception")
      }
      val scope = CoroutineScope(Job() + handler)
      scope.launch {
          throw AssertionError("Test Exception")
      }
      
  • SupervisorJob
    使用 SupervisorJob 隔离子协程的异常影响:

    val supervisor = SupervisorJob()
    with(CoroutineScope(coroutineContext + supervisor)) {
        launch { // 子协程1失败不会影响子协程2
            delay(100)
            throw RuntimeException("Failed")
        }
        launch { 
            delay(200)
            println("Still running")
        }
    }
    

3. 超时控制

通过 withTimeout 或 withTimeoutOrNull 实现超时取消:

// 超时抛出 TimeoutCancellationException
try {
    withTimeout(1000) {
        delay(2000)
    }
} catch (e: TimeoutCancellationException) {
    println("Timed out!")
}

// 超时返回 null
val result = withTimeoutOrNull(1000) {
    delay(2000)
    "Done"
}
println(result) // 输出 null

4. 最佳实践

  • 避免阻塞操作:在协程中使用 suspend 函数替代 Thread.sleep()。
  • 清理逻辑:通过 invokeOnCompletion 注册取消回调。
  • 测试支持:使用 runTest(kotlinx-coroutines-test)模拟协程取消场景。

代码示例

fun main() = runBlocking {
    val job = launch {
        try {
            repeat(1000) { i ->
                ensureActive() // 检查取消状态
                println("Processing $i")
                delay(100)
            }
        } finally {
            println("Cleanup resources")
        }
    }
    delay(250)
    job.cancelAndJoin() // 取消并等待完成
}

注意:协程取消是协作式的,需在协程内部主动检查取消状态或调用可取消的挂起函数(如 delay、yield)。

Last Updated:: 5/21/25, 7:58 PM