Kotlin 中的 协程 基础篇

一、什么叫协程

协程可以称为轻量级线程,线程代码块;

二、GlobalScope 

协程 CoroutineScope (协程作用域) 的上下文中通过 launch、async 等构造器来启动。GlobalScope ,即全局作用域内启动了一个新的协程,这意味这该协程的生命周期只受整个应用程序的生命周期的限制,即只要整个应用程序还在运行中,只要协程的任务还未结束,该协程就可以一直运行。

    //在后台启动一个新协程GlobalScope.launch {delay(3000)//非阻塞式延迟println("World!")}println("Hello ")Thread.sleep(4000)//主线程阻塞 4秒,以此保证JVM 存活

输出:

Hello 
World!

三、runBlocking

非阻塞代码 delay() 和 阻塞代码 Thread.sleep() ,使得我们很容易就搞混当前程序是否是阻塞的,可以改为 runBlocking 来明确这种情形。

fun test2(){GlobalScope.launch {delay(1000)println("World!")}println("Hello ")runBlocking {delay(2000)}
}

运行结果和第一个程序一样,但是这段代码只使用了非阻塞延迟。主线程调用了 runBlocking 函数,直到 runBlocking 内部的所有协程执行完成后,之后的代码才会继续执行。

可以将以上代码用更喜欢方式重写,使用 runBlicking 来包装 main 函数的执行体:

fun test3() {runBlocking<Unit> {GlobalScope.launch {delay(1000)println("World!")}println("Hello ")delay(2000)}
}

需要注意是,runBlocking 代码块默认运行于其声明所在的线程,而 launch 代码块默认运行于线程池中,可以通过打印当前线程名来进行区分。

fun test3() {runBlocking<Unit> {println(Thread.currentThread().name)GlobalScope.launch {println(Thread.currentThread().name)delay(1000)println("World!")}println("Hello ")delay(2000)}
}

 输出:

main  // runblocking 运行 main 线程
Hello 
DefaultDispatcher-worker-1 //GlobalScope 运行线程池
World!

四、job

延迟一段时间等待另一个协程运行并不是一个好的选择,可以显式(非阻塞的方式)地等待协程执行完成

fun test4() {runBlocking {val job = GlobalScope.launch {delay(1000)print("World!")}println("Hello ")job.join()}
}

现在代码的运行结果仍然是相同,但是主协程与后台作业的持续时间没有任何关系,这样好多了。

五、launch

Launch 函数是 CoroutineScope 的扩展函数,而 runBlocking 的函数体参数也是被声明为 CoroutineScope 的扩展函数,所以 launch 函数就隐式持有了和 runBlicking 相同的协程作用域。此时即使 delay 再久, println("World!") 也一定会被执行。

fun test5() {runBlocking {launch {delay(1000)println("World!")}println("Hello ")}
}

六、CoroutineScope

除了使用官方的几个协程构建器之外,还可以使用 coroutineScope 来声明自己的作用域。 coroutineScope 用于创建一个协程作用域,直到所有启动的子协程都完成后才结束。

RunBlocking 和 coroutineScope 看起来很像,因为它们都是需要等待其它内部所有相同作用域的子协程结束后才会结束自己。两者的主要区别在于 runBlocking 方法会阻塞当前线程,而 coroutineScope 只是挂起并释放底层底层线程以供其他协程使用。由于这个差别,所以 runBlocking 是一个普通函数,而 coroutineScope 是一个挂起函数。

fun test6(){runBlocking {//非阻塞 GlobalScopelaunch {delay(200)println("Task from runBlocking")}//非阻塞 coroutineScope {launch {delay(500)println("Task from nested launch")}delay(100)println("Task from coroutine scope")}println("Coroutine scope is over")}
}

 输出:

Task from coroutine scope
Task from runBlocking
Task from nested launch
Coroutine scope is over

六、suspend

 suspend 挂起函数可以想常规函数一样在协程中使用,但是它们的额外特性是:可以依次使用其他挂起函数(如delay函数)来使协程挂起。

fun test7() {runBlocking {//内部调用挂起函数,执行耗时任务launch {doWorld()}println("Hello ")}
}suspend fun doWorld() {delay(1000)println("World!")
}

七、repeat

协程是轻量级的

fun test8() {runBlocking {//启动 10万个协程repeat(100_000) { i ->launch {println("I'm sleeping $i ...")delay(500)}}}
}

八、全局协程类似于守护线程

以下代码在 GlobalScope 中启动了一个会长时间运行的协程,它每秒打印两次,然后延迟一段时间后从 mian 函数返回。

fun test9() {runBlocking {GlobalScope.launch {repeat(1000) { i ->println("I'm sleeping $i ...")delay(500)}}delay(1300)}
}

输出:

I'm sleeping 0 ...
I'm sleeping 1 ...
I'm sleeping 2 ...

这里由于 launch 函数依附的协程作用域是 GlobalScope,而非 runBlocking 所隐含的作用域。在 GlobalScope 中启动的协程无法使进程保持活动状态,它们像守护线程(当主线程消亡时,守护线程也将消亡)

八、协程代码块默认顺序执行

fun test10() {runBlocking {val time = measureTimeMillis {val one = doSomethingUsefulOne()val two = doSomethingUsefulTwo()println("The answer is ${one + two}")}println("Completed in $time ms")}
}suspend fun doSomethingUsefulOne(): Int {delay(1000)return 13
}suspend fun doSomethingUsefulTwo(): Int {delay(1000)return 29
}

 输出:

The answer is 42
Completed in 2011 ms

九、async 

async 实现多个协程异步执行,并可以通过 await() 取出结果返回值,launch 类似 async,但是无返回值。

fun test11(){runBlocking {val time = measureTimeMillis {val one = async { doSomethingUsefulOne() }val two = async { doSomethingUsefulTwo() }println("The answer is ${one.await() + two.await()}")}println("Completed in $time ms")}
}

输出:

The answer is 42
Completed in 1019 ms

十、lazy

async 可以设置 CoroutineStart.lazy 为懒加载模式。在这情况下 需要 调用 await() 或者 start() 才启动。

fun test12(){runBlocking {val time = measureTimeMillis {val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }one.start()two.start()println("The answer is ${one.await() + two.await()}")}println("Completed in $time ms")}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/49988.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSDN编程题-每日一练(2023-08-23)

CSDN编程题-每日一练(2023-08-23) 一、题目名称:圆小艺二、题目名称:连续子数组的最大和三、题目名称:投篮一、题目名称:圆小艺 时间限制:1000ms内存限制:256M 题目描述: 最近小艺酱渐渐变成了一个圆滑的形状-球!! 小艺酱开始变得喜欢上球! 小艺酱得到n个同心圆。 …

构建智慧停车场:4G DTU实现无线数据高速传输

物联网技术的快速发展使得各种设备能够实现互联互通&#xff0c;无线网络技术给我们的日常生活带来了极大的便利。其中的网络技术如无线WiFi及4G网络已经成为了物联网应用中不可或缺的组成部分。而在工业领域中对4G无线路由器的应用是非常广泛的&#xff0c;人们通过4G工业路由…

意外发现Cortex-M内核带的64bit时间戳,比32bit的DWT时钟周期计数器更方便,再也不用担心溢出问题了

视频&#xff1a; https://www.bilibili.com/video/BV1Bw411D7F5 意外发现Cortex-M内核带的64bit时间戳&#xff0c;比32bit的DWT时钟周期计数器更方便&#xff0c;再也不用担心溢出问题了 介绍&#xff1a; 看参数手册的Debug章节&#xff0c;System ROM Table里面带Timestam…

【Java】基础练习(十)

1.判断邮箱 输入一个电子邮箱&#xff0c;判断是否是正确电子邮箱地址。 正确的邮箱地址&#xff1a; 必须包含 字符&#xff0c;不能是开头或结尾必须以 .com结尾和.com之间必须有其他字符 (1) Email类&#xff1a; package swp.kaifamiao.codes.Java.d0823; /** 输入一个…

Android——基本控件下(十七)

1. 文本切换&#xff1a;TextSwitcher 1.1 知识点 &#xff08;1&#xff09;理解TextSwitcher和ViewFactory的使用。 1.2 具体内容 范例&#xff1a;切换显示当前时间 <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools&…

docker安装redis

docker安装redis 一、基本介绍二、前期准备三、docker安装redis3.1 redis镜像拉取3.2 Docker挂载redis配置文件3.3 启动redis容器3.4 验证Redis容器是否正常运行 四、Docker删除Redis容器五、Docker删除Redis镜像 一、基本介绍 Docker 是一个开源的应用容器引擎,参考链接&…

探索最短路径问题:寻找优化路线的算法解决方案

1. 前言&#xff1a;最短路径问题的背景与重要性 在现实生活中&#xff0c;我们常常面临需要找到最短路径的情况&#xff0c;如地图导航、网络路由等。最短路径问题是一个关键的优化问题&#xff0c;涉及在图中寻找两个顶点之间的最短路径&#xff0c;以便在有限时间或资源内找…

时间复杂度与空间复杂度

时间复杂度 时间复杂度是衡量算法运行速度的指标。 常数阶 O(1) 不论算法代码有多少行&#xff0c;只要其中没有循环、递归&#xff0c;按前文所介绍计算方法&#xff0c;其时间复杂度都是Ο(1)。 func calculate(_ num1: Int, _ num2: Int) -> Int {let sum num1 num…

AUTOSAR规范与ECU软件开发(实践篇)5.5 基于ISOLAR-A的系统级设计与配置方法(上)

目录 前言 1 系统配置输入文件创建与导入 2、 Composition SWC建立 前言 如前所述, AUTOSAR支持整车级别的软件架构设计, 开发人员可以进行整车级别的软件组件定义, 再将这些软件组件分配到各个ECU中, 这就是AUTOSAR系统级设计需要完成的主要任务。 下面结合AUTOSAR方法论…

【管理运筹学】第 5 章 | 整数规划 (2,割平面法及 0-1 变量的特性)

文章目录 引言三、割平面法四、0-1 型整数规划4.1 0-1 变量的特性4.1.1 投资问题4.1.2 约束条件满足个数问题 写在最后 引言 前文我们介绍了整数规划的一种求解方法——分支定界法&#xff0c;可以求解纯整数和混合整数规划问题。现在我们来学习另一种整数规划求解方法——割平…

Java 中使用 ES 高级客户端库 RestHighLevelClient 清理百万级规模历史数据

&#x1f389;工作中遇到这样一个需求场景&#xff1a;由于ES数据库中历史数据过多&#xff0c;占用太多的磁盘空间&#xff0c;需要定期地进行清理&#xff0c;在一定程度上可以释放磁盘空间&#xff0c;减轻磁盘空间压力。 &#x1f388;在经过调研之后发现&#xff0c;某服务…

[Ubuntu 20.04 PC] 安装C-Kermit:一个开源串口通信软件

在计算机科学领域,串口通信一直是非常重要的一环。而C-Kermit作为一款强大而灵活的开源串口通信软件,广泛应用于UNIX、Linux和Windows等操作系统中。本文将介绍C-Kermit的基本原理、特点以及如何使用它进行串口通信。 一、C-Kermit的基本原理 C-Kermit是由C语言实现的,旨在…

MyBatid动态语句且模糊查询

目录 什么是MyBtais动态语句&#xff1f;&#xff1f;&#xff1f; MyBatis常用的动态标签和表达式 if标签 Choose标签 where标签 MyBatis模糊查询 #与$的区别 ​编辑 MyBatis映射 resultType resultMap 什么是MyBtais动态语句&#xff1f;&#xff1f;&#xff1f;…

TensorFlow 介绍

TensorFlow 是一个开源的机器学习框架&#xff0c;由 Google 开发。它支持多种机器学习和深度学习算法&#xff0c;包括神经网络、卷积神经网络、循环神经网络等。TensorFlow 利用数据流图的形式来表达计算&#xff0c;将输入数据和计算操作表示为节点&#xff0c;建立 TensorF…

2023-08-23力扣每日一题

链接&#xff1a; 1782. 统计点对的数目 题意&#xff1a; 给n个点和m条无向边&#xff08;可重复&#xff09;&#xff0c;q个查询 定义edge[a]为一个点是a的边数量&#xff0c;定义ret[a,b]是edge[a]edge[b]-&#xff08;a与b的边&#xff09; q个查询q个答案&#xff0…

视频转音频mp3怎么弄?

视频转音频mp3怎么弄&#xff1f;在很多人看来&#xff0c;音频就是视频中的一部分&#xff0c;其实这时是一定道理的&#xff0c;视频是一种包含图像和有声音的多媒体文件&#xff0c;没有声音的视频是不完美的。时代发展到现在&#xff0c;短视频已经融入了我们生活的方方面面…

【日常积累】Linux中vi/vim的使用

概述 vim是由vi发展演变过来的文本编辑器&#xff0c;因其具有语法高亮显示、多视窗编辑、代码折叠、支持插件等功能&#xff0c;由于其功能相比vi来说更加强大&#xff0c;所以在实际工作中的使用更加广泛。 vim工作模式 Vim具有多种工作模式&#xff0c;常用的工作模式有&…

微服务架构2.0--云原生时代

云原生 云原生&#xff08;Cloud Native&#xff09;是一种关注于在云环境中构建、部署和管理应用程序的方法和理念。云原生应用能够最大程度地利用云计算基础设施的优势&#xff0c;如弹性、自动化、可伸缩性和高可用性。这个概念涵盖了许多方面&#xff0c;包括架构、开发、…

Prometheus+Grafana+AlertManager监控Linux主机状态

文章目录 PrometheusGrafanaAlertManager监控平台搭建开始监控Grafana连接Prometheus数据源导入Grafana模板监控Linux主机状态 同系列文章 PrometheusGrafanaAlertManager监控平台搭建 Docker搭建并配置Prometheus Docker拉取并配置Grafana Docker安装并配置Node-Exporter …

Python系统学习1-9-类三之特征

一、封装 数据角度&#xff1a;将一些基本数据类型复合成一个自定义类型。 优势&#xff1a;将数据与对数据的操作相关联。 代码可读性更高&#xff08;类是对象的模板&#xff09;。 行为角度&#xff1a;向类外提供必要的功能&#xff0c;隐藏实现的细节。 优势&#xff…