当前位置:首页 > 技术 > 正文内容

Kotlin协程实战:实现高效轻量的并发编程

访客 技术 2026年6月27日 1

协程与传统线程的本质区别

在现代应用开发中,处理并发任务时选择合适的机制至关重要。传统的 Java 线程由操作系统直接管理,每个线程通常占用约 1MB 栈内存,创建成本高且难以大规模使用。

而 Kotlin 协程采用用户态调度,仅需几 KB 内存即可创建,支持百万级并发任务而不引发内存溢出。

// 传统线程方式(容易崩溃)
for (i in 0 until 10_000) {
    Thread { performTask() }.start()
}

// 协程方式(流畅运行)
repeat(100_000) {
    GlobalScope.launch { performTask() }
}

快速入门:构建首个协程

通过 runBlocking 启动一个协程,它会阻塞当前线程直到内部协程完成。

fun main() = runBlocking {
    launch {
        delay(1_000) // 非阻塞等待
        println("World!")
    }
    println("Hello,")
}
// 输出顺序:
// Hello,
// (1秒后)World!

作用域管理:控制协程生命周期

协程的作用域决定了其生命周期和执行上下文:

  • GlobalScope:全局作用域,不受控,适合短时任务
  • runBlocking:阻塞调用方线程,直到协程结束
  • coroutineScope:挂起当前协程,等待所有子协程完成
  • viewModelScope(Android):绑定到 ViewModel,自动清理
suspend fun fetchUserData() = coroutineScope {
    val userJob = async { fetchUserInfo() }
    val orderJob = async { fetchUserOrders() }

    Pair(userJob.await(), orderJob.await())
}

挂起函数:异步操作的同步写法

使用 suspend 修饰符定义的函数可在协程中暂停执行,但不会阻塞底层线程。

suspend fun retrieveProfile(): UserProfile {
    return withContext(Dispatchers.IO) {
        networkClient.get("/profile")
    }
}

fun loadProfile() = viewModelScope.launch {
    showProgress()
    val profile = retrieveProfile() // 暂停等待结果
    updateDisplay(profile)
    hideProgress()
}

调度器:精准分配执行环境

不同场景应使用不同的调度策略:

  • Dispatchers.Main:用于 UI 更新
  • Dispatchers.IO:处理 I/O 操作(网络、文件)
  • Dispatchers.Default:执行计算密集型任务
  • 自定义线程池:如固定大小的线程池
val customPool = Executors.newFixedThreadPool(4).asCoroutineDispatcher()

withContext(customPool) {
    processLargeData()
}

异常处理机制

协程支持全局与局部异常捕获,提升程序健壮性。

val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
    logError(throwable)
}

val job = GlobalScope.launch(exceptionHandler) {
    throw IllegalStateException("Something went wrong")
}

// 局部异常处理
try {
    val result = async { riskyOperation() }.await()
} catch (e: Exception) {
    handleFailure(e)
}

实战案例:并行加载多源数据

利用 asyncawait 可轻松实现多个请求并行执行。

suspend fun loadAllData(userId: Int): UserDataResult {
    return coroutineScope {
        val userInfo = async { fetchUser(userId) }
        val recentOrders = async { fetchRecentOrders(userId) }
        val preferences = async { fetchPreferences(userId) }

        UserDataResult(
            user = userInfo.await(),
            orders = recentOrders.await(),
            prefs = preferences.await()
        )
    }
}

相比 Java 的 CompletableFuture,Kotlin 协程以更直观的结构化方式表达异步逻辑,避免回调嵌套。

核心优势总结

  • 极低开销:可轻松创建数十万并发任务
  • 结构化并发:作用域自动管理协程生命周期
  • 非阻塞挂起:用同步风格编写异步代码
  • 灵活调度:按任务类型分配执行线程
标签: Kotlin

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。