Kotlin 协程之launch、async、suspend 函数和调度器(Dispatchers)

在 Kotlin 协程中,launchasyncsuspend 函数和调度器(Dispatchers)是核心组件,它们共同实现了轻量级的并发编程。以下是详细解析和使用示例:

一、协程基础概念

协程是一种轻量级线程,由 Kotlin 运行时管理(而非操作系统),可以在单线程内实现多任务切换,避免线程上下文切换的开销。

二、suspend 函数:协程的 "暂停点"

suspend 是用于修饰函数的关键字,标记该函数只能在协程或其他 suspend 函数中调用,且内部可以 "暂停" 执行(不会阻塞线程)。

  • 特性
    • 暂停时会保存当前状态(局部变量、执行位置等),恢复时继续执行。
    • 本身不会创建协程,仅标记可暂停的操作(如网络请求、IO 等)。

kotlin

复制代码
// 定义 suspend 函数(模拟耗时操作)
suspend fun fetchData(): String {
    delay(1000) // delay 是 Kotlin 提供的 suspend 函数,模拟暂停(非阻塞)
    return "Data from network"
}
  • 注意suspend 函数不能直接在主线程(非协程)中调用,必须通过协程构建器启动。

三、协程构建器:launchasync

用于创建并启动协程,最常用的是 launchasync

1. launch:启动 "无返回值" 的协程
  • 作用:启动一个协程,返回 Job 对象(用于管理协程生命周期,如取消、等待)。
  • 适用场景:执行不需要返回结果的后台任务(如日志打印、数据保存)。

kotlin

复制代码
import kotlinx.coroutines.*

fun main() = runBlocking { // runBlocking 是顶层函数,用于在非协程环境启动协程(会阻塞当前线程直到内部协程完成)
    // 启动一个协程
    val job = launch {
        println("Coroutine started")
        delay(1000) // 暂停 1 秒(非阻塞)
        println("Coroutine finished")
    }
    
    job.join() // 等待协程执行完成(阻塞当前协程,非线程)
    println("Main finished")
}
  • 输出: plaintext

    复制代码
    Coroutine started
    Coroutine finished
    Main finished
2. async:启动 "有返回值" 的协程
  • 作用:启动一个协程,返回 Deferred<T> 对象(Job 的子类),通过 await() 获取返回值(T 类型)。
  • 适用场景:需要获取结果的异步任务(如并行请求多个接口)。

kotlin

复制代码
fun main() = runBlocking {
    // 启动带返回值的协程
    val deferred = async {
        delay(1000)
        42 // 返回值
    }
    
    val result = deferred.await() // 等待结果(非阻塞,会暂停当前协程)
    println("Result: $result") // 输出:Result: 42
}
  • 并行执行async 适合并行任务,多个 async 可同时执行,最后用 await() 汇总结果:

kotlin

复制代码
fun main() = runBlocking {
    val time = measureTimeMillis { // 测量执行时间
        val deferred1 = async { fetchData1() }
        val deferred2 = async { fetchData2() }
        // 并行执行,总时间约为较慢任务的时间(而非两者之和)
        val result1 = deferred1.await()
        val result2 = deferred2.await()
        println("Total: $result1 + $result2 = ${result1 + result2}")
    }
    println("Time: $time ms") // 约 2000 ms(因 fetchData2 耗时 2 秒)
}

suspend fun fetchData1(): Int {
    delay(1000)
    return 100
}

suspend fun fetchData2(): Int {
    delay(2000)
    return 200
}

四、调度器(Dispatchers):指定协程运行的线程

协程需要运行在调度器指定的线程池上,Kotlin 提供了几种内置调度器:

调度器 作用 适用场景
Dispatchers.Main 主线程(Android 中是 UI 线程) 更新 UI(需依赖 Android 库)
Dispatchers.IO IO 线程池(网络、文件读写等) 耗时 IO 操作
Dispatchers.Default CPU 密集型任务线程池(默认) 计算密集型任务(如数据处理)
Dispatchers.Unconfined 不指定线程(在当前线程执行,暂停后恢复到 resume 线程) 特殊场景(谨慎使用)
使用方式:通过 CoroutineContext 指定

协程构建器(launch/async)可通过参数指定调度器:

kotlin

复制代码
fun main() = runBlocking {
    // 1. IO 调度器(处理网络请求)
    launch(Dispatchers.IO) {
        println("IO thread: ${Thread.currentThread().name}") // 输出:IO thread: DefaultDispatcher-worker-1
        fetchData()
    }.join()

    // 2. Default 调度器(处理计算任务)
    val result = async(Dispatchers.Default) {
        println("Default thread: ${Thread.currentThread().name}") // 输出:Default thread: DefaultDispatcher-worker-2
        1 + 1
    }.await()
    println("Result: $result")
}

五、协程上下文(CoroutineContext

调度器是 CoroutineContext 的一部分,上下文还包括 Job(协程生命周期)、CoroutineName(协程名称,用于调试)等。可通过 + 组合多个上下文元素:

kotlin

复制代码
fun main() = runBlocking {
    launch(Dispatchers.IO + CoroutineName("NetworkCoroutine")) {
        println("Name: ${coroutineContext[CoroutineName]}") // 输出:Name: CoroutineName(NetworkCoroutine)
        fetchData()
    }.join()
}

六、关键区别总结

组件 作用 返回值 适用场景
suspend 标记可暂停的函数 无(函数自身有返回值) 定义耗时操作
launch 启动无返回值的协程 Job 后台任务(无结果)
async 启动有返回值的协程 Deferred<T> 需结果的异步任务
Dispatchers 指定协程运行的线程池 - 控制任务执行的线程环境

七、注意事项

  1. runBlocking 的使用:仅用于测试或 main 函数,会阻塞当前线程,生产环境(如 Android)中避免使用。
  2. await() 的位置asyncawait() 应在需要结果时调用,过早调用会导致串行执行(失去并行优势)。
  3. 取消协程 :通过 Job.cancel() 取消协程,需确保 suspend 函数能响应取消(如 delay 是可取消的)。
  4. Android 中的主线程Dispatchers.Main 需要依赖 androidx.lifecycle:lifecycle-viewmodel-ktx 等库。

通过合理组合这些组件,可以高效实现异步、非阻塞的并发逻辑,避免传统线程模型的性能开销

相关推荐
错把套路当深情3 小时前
Kotlin基础类型扩展函数使用指南
python·微信·kotlin
错把套路当深情17 小时前
Kotlin Map扩展函数使用指南
服务器·前端·kotlin
消失的旧时光-194317 小时前
Kotlin 协程实践:深入理解 SupervisorJob、CoroutineScope、Dispatcher 与取消机制
android·开发语言·kotlin
错把套路当深情17 小时前
Kotlin List扩展函数使用指南
开发语言·kotlin·list
佳哥的技术分享18 小时前
kotlin基于MVVM架构构建项目
android·开发语言·kotlin
雨白1 天前
玩转 Flow 操作符(二):时间控制、聚合与组合
android·kotlin
程序员江同学1 天前
Kotlin 技术月报 | 2025 年 10 月
android·kotlin
天花板之恋1 天前
MutableStateFlow、StateFlow、LiveData在Compose中的运用
kotlin·workflow
alexhilton2 天前
Compose CameraX现已稳定:给Composer的端到端指南
android·kotlin·android jetpack