Kotlin 协程(三)协程的常用关键字使用及其比较

在使用协程时,经常会用到suspendlaunchasyncawaitwithContextrunBlocking这些关键字,这儿对其进行解释和比较

为了更好地理解 suspendlaunchasyncawaitwithContextrunBlocking 之间的区别,我们可以从 挂起、协程启动、作用域管理 等方面进行对比。

1. suspend 关键字(挂起与恢复)

  • suspend 关键字用于 定义挂起函数 ,表示该函数可以在非阻塞的情况下暂停(挂起)并恢复。
  • 挂起函数只能在 协程或其他挂起函数 中调用。
  • 挂起时不会阻塞线程,而是让出线程,允许其他协程执行。

2. launch(启动一个新的协程,返回 Job

  • launch 创建 并启动一个新的协程 但不会返回结果
  • 适用于 不需要返回值,例如更新 UI、写日志等。
  • 返回一个 Job,可以用 job.cancel() 取消该协程。

3. async & await(并发执行任务,返回 Deferred<T>

  • async 启动 并发任务 并返回一个 Deferred<T> (类似于 Future)。
  • await() 用于获取 async 返回的结果 ,如果任务未完成,它会挂起协程直到完成。
Kotlin 复制代码
suspend fun loadData(): String {
    return withContext(Dispatchers.IO) {
        delay(1000)
        "Data loaded"
    }
}

suspend fun testAsync() {
    val deferred1 = async { loadData() }
    val deferred2 = async { loadData() }

    // await() 取出结果
    val result1 = deferred1.await()
    val result2 = deferred2.await()
    
    println("Result: $result1, $result2")
}
  • 需要 并行执行多个任务 并等待结果:
    • 多个网络请求
    • 批量数据库查询
    • 计算密集型任务

async 类似于 launch,但它返回结果launch 只是执行,不返回值。

4. withContext(切换协程上下文,执行完成后返回结果)

  • withContext 切换 到指定的调度器(线程池),执行代码块,并返回结果。
  • 等待代码块执行完成后再继续 ,不会创建新的协程,而是挂起当前协程并切换线程
Kotlin 复制代码
suspend fun fetchData(): String {
    return withContext(Dispatchers.IO) {  // 切换到 IO 线程
        delay(1000)
        "Fetched Data"
    }
}
  • 切换线程池 ,适用于:
    • 网络请求(Dispatchers.IO
    • 数据库查询(Dispatchers.IO
    • 计算密集型任务(Dispatchers.Default

withContext 不会并发执行 ,它只是切换线程,等任务完成后再返回。

Dispatchers 预定义调度器

调度器 作用 适用场景
Dispatchers.Default 适用于 CPU 密集型任务(计算、加密等) 计算任务,如排序、数学运算等
Dispatchers.IO 适用于 I/O 操作(磁盘、网络、数据库) 读写文件、数据库查询、网络请求
Dispatchers.Main 适用于 Android 主线程 更新 UI,处理用户交互
Dispatchers.Unconfined 继承调用方线程,恢复时可能切换线程 测试或临时任务,不建议使用
newSingleThreadContext("MyThread") 自定义单线程调度器 特定线程执行任务

5. launch vs async vs withContext 对比

关键字 是否返回结果 适用场景 线程调度
launch ❌ 不返回结果 执行任务但不关心结果 不切换线程
async ✅ 返回 Deferred<T> 并发执行多个任务并等待结果 不切换线程
withContext ✅ 返回结果 切换线程并执行任务 切换线程

6.runBlocking 详解

runBlocking 是 Kotlin 协程中的一个函数,它 阻塞当前线程 并运行一个新的协程,直到该协程及其子协程执行完毕后才会继续执行后续代码。一般不会用到,只要用于测试

Kotlin 复制代码
fun main() {
    runBlocking {
        println("协程开始")
        delay(1000)
        println("协程结束")
    }
    println("主线程继续执行")
}

执行流程

  1. runBlocking 启动 一个协程 并阻塞当前线程 (如 main 线程)。
  2. delay(1000) 挂起协程 ,但 runBlocking 仍然阻塞 线程,其他代码不会执行。
  3. 协程执行完 delay(1000) 之后,继续执行 println("协程结束")
  4. runBlocking 结束后,主线程才会继续执行 println("主线程继续执行")
Kotlin 复制代码
fun main() {
    runBlocking {
        launch {
            delay(1000)
            println("子协程完成")
        }
        println("runBlocking 结束")
    }
    println("主线程继续")
}

执行流程

  1. runBlocking 启动 一个主协程 ,阻塞 main 线程。
  2. launch 创建一个子协程 ,但 launch 不会阻塞 runBlocking,它只是异步执行。
  3. println("runBlocking 结束") 立即执行,不等待 launch 内部的 delay(1000)
  4. runBlocking 结束后main 线程继续执行 println("主线程继续")
  5. launch 子协程在后台继续运行 ,1 秒后打印 "子协程完成"

7.启动新协程

关键字 作用 返回值 是否阻塞线程 适用于
launch 启动一个新的协程,异步执行代码 Job ❌ 否 适合不需要返回值的任务
async 启动一个新的协程,返回 Deferred Deferred<T> ❌ 否 适合需要返回值的任务

8. 作用域管理

关键字 作用 是否阻塞线程 适用于
runBlocking 阻塞当前线程,启动协程 ✅ 是 main 函数、单元测试
coroutineScope 创建新的协程作用域,等待所有子协程完成 ❌ 否 挂起函数内部管理协程
withContext 在指定调度器中切换上下文并执行代码 ❌ 否 线程切换(如 IO 线程)

总结

关键字 作用 是否阻塞线程 是否创建新协程 适用于
suspend 让函数支持挂起 ❌ 否 ❌ 否 定义可挂起函数
launch 启动一个协程,无返回值 ❌ 否 ✅ 是 异步执行无返回值任务
async 启动一个协程,返回 Deferred<T> ❌ 否 ✅ 是 计算任务,需要返回值
await 挂起当前协程,等待 async 结果 ❌ 否 ❌ 否 获取 async 结果
runBlocking 启动协程并阻塞线程 ✅ 是 ✅ 是 main 函数、测试
coroutineScope 创建作用域,等待所有协程 ❌ 否 ❌ 否 在挂起函数内部管理协程
withContext 切换协程执行的线程 ❌ 否 ❌ 否 线程切换,如 Dispatchers.IO
相关推荐
努力的lpp5 分钟前
php反序列化一(大白话版)
开发语言·web安全·php·ctf·反序列化
菜鸟~noob23313 分钟前
【电子战】第03篇:CFAR(恒虚警)处理【含matlab代码】
开发语言·matlab
flower_drop1 小时前
基于 WebUSB 与 CDP:在浏览器端实现 Android 设备通信与无证书抓包实践
android·chrome·测试工具·adb·bug·edge浏览器
泡海椒1 小时前
内置SPI函数库详解:JQuick-Java Builtin工具类实战用法
java·开发语言·python
hqyjzsb1 小时前
零 AI 项目经验,学 Python 转型 AI 的正确顺序是什么?
开发语言·人工智能·python·算法·职场和发展·数据挖掘·数据分析
Keven_112 小时前
算法札记:ACM适用的很骚的C++语法(持续更新)
开发语言·c++
脉动数据行情13 小时前
C# 实现德指 DAX 期货 WebSocket 实时行情监听
开发语言·websocket·c#
撩得Android一次心动3 小时前
Jetpack Compose 知识点整理1【个人用】
android·学习·kotlin·android jetpack·compose
大圣编蚕3 小时前
Java ByteArrayInputStream 详解:从入门到实战
java·开发语言·算法
菜鸟~noob2333 小时前
【电子战】第02篇:能量检测器 vs. 相关检测器【含matlab代码】
开发语言·matlab