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 等库。

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

相关推荐
Propeller14 小时前
【Kotlin】Kotlin 基础语法:变量、控制和函数
kotlin
Rysxt_1 天前
Kotlin前景深度分析:市场占有、技术优势与未来展望
android·开发语言·kotlin
莫白媛1 天前
Android开发之Kotlin 在 Android 开发中的全面指南
android·开发语言·kotlin
天勤量化大唯粉2 天前
基于距离的配对交易策略:捕捉价差异常偏离的均值回归机会(天勤量化代码实现)
android·开发语言·python·算法·kotlin·开源软件·策略模式
hudawei9962 天前
kotlin冷流热流的区别
android·开发语言·kotlin·flow··冷流·热流
hudawei9962 天前
对比kotlin和flutter中的异步编程
开发语言·flutter·kotlin·异步·
モンキー・D・小菜鸡儿2 天前
Android11 新特性与适配指南
android·kotlin·安卓新特性
starrycode8883 天前
【每日一个知识点】Kotlin基础语法核心学习笔记
笔记·学习·kotlin
alexhilton3 天前
学会在Jetpack Compose中加载Lottie动画资源
android·kotlin·android jetpack
用户69371750013844 天前
29.Kotlin 类型系统:智能转换:类型检查 (is) 与类型转换 (as)
android·后端·kotlin