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
  • 协程上下文与调度器

协程上下文与调度器

1. 什么是协程上下文?

协程上下文(CoroutineContext)是协程运行时的环境配置,它定义了协程的行为和调度方式。每个协程都关联一个上下文,包含以下关键元素:

  • 调度器(Dispatcher):决定协程在哪个线程或线程池上执行
  • Job:控制协程的生命周期
  • 异常处理器(CoroutineExceptionHandler):处理未捕获的异常
  • 协程名称(CoroutineName):用于调试的标识符
val context = Dispatchers.Default + Job() + CoroutineName("MyCoroutine")

2. 调度器的类型与使用

Kotlin 提供了四种标准调度器:

调度器用途适用场景
Dispatchers.DefaultCPU 密集型任务计算、排序、算法处理
Dispatchers.IOI/O 密集型任务网络请求、文件操作
Dispatchers.MainUI 线程(需依赖相应平台)Android/JavaFX/Swing UI 更新
Dispatchers.Unconfined不限定线程特殊场景(一般不推荐)
// 示例:在不同调度器间切换
launch(Dispatchers.Default) {
    // CPU 密集型计算
    withContext(Dispatchers.IO) {
        // 网络请求
    }
    withContext(Dispatchers.Main) {
        // 更新UI
    }
}

3. 自定义调度器

可以通过 Executors 创建自定义线程池:

val customDispatcher = Executors.newFixedThreadPool(4).asCoroutineDispatcher()

// 使用后需要关闭(防止内存泄漏)
customDispatcher.close()

4. 上下文继承与覆盖

协程上下文遵循继承规则:

  • 子协程默认继承父协程的上下文
  • 可以通过参数显式覆盖特定元素
val parentJob = Job()
val scope = CoroutineScope(Dispatchers.Main + parentJob)

scope.launch(Dispatchers.IO) {
    // 这里调度器被覆盖为IO,但仍继承parentJob
}

5. 调试技巧

使用 CoroutineName 和系统属性调试协程:

// 1. 为协程命名
launch(CoroutineName("NetworkRequest")) { ... }

// 2. 启用调试模式(VM参数)
-Dkotlinx.coroutines.debug=on

6. 最佳实践

  1. 避免硬编码调度器:通过参数或依赖注入传递调度器
  2. 注意生命周期管理:在 Android 的 ViewModel 中使用 viewModelScope
  3. 资源释放:自定义调度器使用后需要关闭
  4. 避免过度切换:减少不必要的上下文切换开销
// ViewModel 中的推荐用法
viewModelScope.launch {
    // 自动绑定ViewModel生命周期
}

常见问题

Q:如何选择正确的调度器? A:遵循以下原则:

  • UI 操作 → Dispatchers.Main
  • 文件/网络 → Dispatchers.IO
  • 复杂计算 → Dispatchers.Default

Q:Unconfined 调度器何时使用? A:仅在确定协程不会消耗大量时间且不需要特定线程时才使用,常见于测试场景。

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