Kotlin 异步编程:完整实践指南
现代应用程序需要高性能和快速响应。借助协程(coroutines)的 Kotlin 异步编程已成为处理网络请求、数据库和文件操作的事实标准。在本指南中,我们将解析核心概念,展示实战示例,并提供可直接用于项目的现成模板。
1. Kotlin 协程基础
协程是轻量级线程,允许在不阻塞主线程的情况下暂停函数执行。与传统线程不同,协程可以在任意时刻暂停并在之后恢复,使其成为异步操作的理想选择。
1.1. 添加依赖
首先,在 build.gradle.kts 中添加依赖:
dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0") // 用于 Android}1.2. 第一个协程
使用 runBlocking 创建一个简单的协程——它是同步世界与异步世界之间的桥梁:
import kotlinx.coroutines.*
fun main() = runBlocking { launch { delay(1000L) // 非阻塞延迟 println("世界!") } println("你好,") delay(2000L) // 等待协程完成}在这个示例中,launch 启动了一个新协程,而 delay 是一个不会阻塞线程的挂起函数(suspend)。
2. Suspend 函数与结构化并发
2.1. 创建 suspend 函数
任何可以被暂停的函数都必须使用 suspend 修饰符标记。此类函数只能从协程或其他 suspend 函数中调用:
suspend fun fetchUserData(userId: String): User { delay(2000L) // 模拟网络请求 return User(userId, "伊万·彼得罗夫")}
suspend fun fetchUserPosts(userId: String): List<Post> { delay(1500L) return listOf(Post("标题 1"), Post("标题 2"))}2.2. 顺序执行
默认情况下,协程在同一个 launch 内按顺序执行:
fun main() = runBlocking { val time = measureTimeMillis { val user = fetchUserData("123") val posts = fetchUserPosts("123") println("${user.name} 有 ${posts.size} 篇帖子") } println("执行时间:$time 毫秒") // ~3500 毫秒}2.3. 使用 async/await 并行执行
使用 async 和 await 实现并行执行:
fun main() = runBlocking { val time = measureTimeMillis { val user = async { fetchUserData("123") } val posts = async { fetchUserPosts("123") } println("${user.await().name} 有 ${posts.await().size} 篇帖子") } println("执行时间:$time 毫秒") // ~2000 毫秒(并行)}3. 协程调度器与上下文
调度器决定了协程在哪个线程或线程池上执行。主要调度器包括:
- Dispatchers.Default — 用于 CPU 密集型任务(默认)
- Dispatchers.IO — 用于输入/输出操作(网络、文件)
- Dispatchers.Main — 用于 UI 线程(Android、Swing)
- Dispatchers.Unconfined — 不绑定到特定线程
3.1. Dispatchers.IO 示例
fun main() = runBlocking { launch(Dispatchers.IO) { // 网络请求 val response = httpClient.get("https://api.example.com/data") withContext(Di