【Kotlin】协程

Kotlin协程

背景

在项目实践过程中,笔者发现很多异步或者耗时的操作,都使用了Kotlin中的协程,所以特地研究了一番。

定义

关于协程(Coroutine),其实更多的应该是一种并发设计模式。与传统的线程或进程相比,协程更加轻量级,因为它运行在线程之上,在执行过程中可以主动地暂停,并在需要时恢复执行。而且这些切换操作是在操作系统中的用户态完成的。

实践

  • 引入maven依赖:
bash 复制代码
<dependency>
	<groupId>org.jetbrains.kotlinx</groupId>
	<artifactId>kotlinx-coroutines-core</artifactId>
</dependency>
  • 两种启动模式
    • runBlocking
    • GlobalScope.launch

GlobalScope.launch

GlobalScope.launch 中启动的协程不会阻塞主线程。主线程会继续执行,而协程会在后台执行。在上述例子中,为了演示效果,使用了 Thread.sleep(2000) 来模拟等待协程执行。

其中,launch 是一个函数,用于创建协程并将其函数主体的执行分派给相应的调度程序。

bash 复制代码
fun main() {
    // 启动协程
    GlobalScope.launch {
        delay(2000) // 挂起协程,模拟异步操作
        println("World!")
    }

    println("Hello,")
    Thread.sleep(4000) // 阻塞主线程,等待协程执行完毕
}

runBlocking

runBlocking 中启动的协程会阻塞当前线程,直到所有启动的协程都执行完毕。

bash 复制代码
fun main() = runBlocking {
    // 在 runBlocking 作用域内启动协程
    launch {
        // 协程代码
        println("Inside coroutine")
    }

    // 主线程继续执行
    println("Outside coroutine")

    // 阻塞主线程,等待协程执行完毕
}

业务实践

  • Dispatchers.IO Kotlin提供的协程调度方式,指示此协程应在为 I/O 操作预留的线程上执行,适合在主线程之外执行磁盘或网络 I/O。
  • Dispatchers.Main 使用此调度程序可在主线程上运行协程。(在官方文档介绍中,主要用于安卓开发中,与界面交互和执行快速工作。)
  • Dispatchers.Default 适合在主线程之外执行占用大量 CPU 资源的工作。
bash 复制代码
private fun sendRefundHttpPost(weChatPayRefundUrl: String, xmlRequestData: String): Map<String, String> = runBlocking {
      // 启用协程发送退款操作
        return@runBlocking withContext(Dispatchers.IO) {
            val responseXmlStr = careWeChatHttps.postXmlForString(weChatPayRefundUrl, xmlRequestData)
            WXPayUtil.xmlToMap(responseXmlStr)
        }
    }
bash 复制代码
 private fun getSchoolDate(allTeacherIds: Set<String>): WildSchoolData = runBlocking {
       // 涉及统计的allTeacherIds 数量比较大, 创建异步任务去操作
        val elements = allTeacherIds.chunked(60).map {
            async(Dispatchers.Default) {
                val totalCount = teacherPerformanceServiceApi.getTeachersTotalPerformanceCount(it).performanceCount
                val currentWeekCount = teacherPerformanceServiceApi.getTeachersCurrentWeekPerformanceCountByByRangeTime(it).performanceCount
                WildSchoolData(totalCount, currentWeekCount)
            }
        }
        // 调用await等待异步任务结束
        return@runBlocking WildSchoolData(elements.awaitAll().sumBy { it.totalCount }, elements.awaitAll().sumBy { it.currentWeekCount })
    }
bash 复制代码
    fun savePoint(pagePointVo: PagePointVo): Any {
       // 启用协程执行一个操作流水的插入, 不影响其他操作
        GlobalScope.launch(context = Dispatchers.IO) {
            val pagePoint = PagePoint().apply {
                this.schoolId = pagePointVo.schoolId
                this.userId = pagePointVo.userId
                this.userRole = pagePointVo.userRole
                this.moduleKey = pagePointVo.moduleKey
                this.eventId = pagePointVo.eventId
                this.clickTime = Date()
            }
            pagePointMapper.insert(pagePoint)
        }
        // 其他操作
    }
相关推荐
Jinkxs4 分钟前
Java 架构 02:DDD 领域模型设计实战(限界上下文划分)
java·开发语言·架构
木易 士心5 分钟前
MVC、MVP 与 MVVM:Android 架构演进之路
android·架构·mvc
百锦再7 分钟前
国产数据库的平替亮点——关系型数据库架构适配
android·java·前端·数据库·sql·算法·数据库架构
走在路上的菜鸟10 分钟前
Android学Dart学习笔记第十三节 注解
android·笔记·学习·flutter
毕设源码-钟学长28 分钟前
【开题答辩全过程】以 基于PHP的家常菜谱教程网站为例,包含答辩的问题和答案
开发语言·php
消失的旧时光-194333 分钟前
用 C 实现一个简化版 MessageQueue
c语言·开发语言
小鹿学程序33 分钟前
jdk配置完之后java -version还是默认的jdk版本如何更改
java·开发语言·python
至善迎风34 分钟前
Bun:下一代 JavaScript 运行时与工具链
开发语言·javascript·ecmascript·bun
介一安全37 分钟前
【Frida Android】实战篇15:Frida检测与绕过——基于/proc/self/maps的攻防实战
android·网络安全·逆向·安全性测试·frida
程序员-King.37 分钟前
【Qt开源项目】— ModbusScope-day 5
开发语言·qt