Kotin协程的基础

news2024/11/20 11:32:01
协程是什么?

      就是同步方式去编写异步执行的代码。协程是依赖于线程,但是协程挂起的时候不需要阻塞线程。几乎没有任何代价。

协程的创建

      一个线程可以创建多个协程。协程的创建是通过CoroutineScope创建,协程的启动方式有三种。

  1. runBlocking: T 启动一个新的协程并阻塞调用它的线程,直到协程里面的代码执行完毕,返回值是范型T,就是协程体中最后一行返回的是什么类型,那么T就是什么类型。
  2. launch: job 启动一个协程但不会阻塞调用它的线程,必须在协程作用域(CoroutineScope)中才能调用,返回的是一个job。
  3. async: Deferred<T>启动一个协程但不会阻塞调用它的线程,必须在协程作用域(CoroutineScope)中才能调用。以Deferred对象的形式返回协程任务。返回值范型T同runBlocking类似都是协程体的最后一行。

上述内容提到了Job、Deferred,它们是什么东西呢?

job

       job可以认为就是一个协程作业是通过CoroutineScope.launch生成,同时它运行一个指定的代码块,并在该代码块完成时完成。可以通过isActive、isCompleted、isCancelled来获取Job当前状态。

截屏2023-07-26 22.59.32.png

Deferred

Deferred继承job,可以把它看成一个带有返回值的job

public interface Deferred<out T>: job {
    // 返回结果值,或者如果延迟被取消,则抛出响应的异常
    public suspend fun await(): T
    public val onAwait: SelectClause1<T>
    public fun getCompleted(): T
    public fun getCompletionExceptionOrNull():Trowable?
}

作用域

        协程作用域(CoroutineScope)是协程运行的作用范围。launch、async都是CoroutineScope的扩展函数。CoroutineScope定义了新启动的协程作用域范围,同时会继承了它的CoroutineContext自动传播其所有的elements和取消操作。也就是说,如果这个作用域销毁了,那么里面的协程也就失效了

协程的基础用法
private fun start(){
    val runBlockingJob = runBlocking {
        Log.d("runBlocking", "启动一个协程")
        41
    }
    Log.d("runBlockingJob", "$runBlockingJob")
    val launchJob = GlobalScope.launch{
        Log.d("launch", "启动一个协程")
    }
    Log.d("launchJob", "$launchJob")
    val asyncJob = GlobalScope.async{
        Log.d("async", "启动一个协程")
        "我是返回值"
    }
    Log.d("asyncJob", "$asyncJob")
}

输出为:

D/runBlocking: 启动一个协程
D/runBlockingJob: 41
D/launchJob: StandaloneCoroutine{Active}@3b8b871
D/launch: 启动一个协程
D/async: 启动一个协程
D/asyncJob: DeferredCoroutine{Active}@63f2656

或者

D/runBlocking: 启动一个协程
D/runBlockingJob: 41
D/launchJob: StandaloneCoroutine{Active}@1344515
D/asyncJob: DeferredCoroutine{Active}@38c002a
D/async: 启动一个协程
D/launch: 启动一个协程

或者

D/runBlocking: 启动一个协程
D/runBlockingJob: 41
D/launch: 启动一个协程
D/launchJob: StandaloneCoroutine{Active}@b94e973
D/async: 启动一个协程
D/ asyncJob: DeferredCoroutine{Active}@f7aa030

        由于runBlocking启动的是一个新的协程并阻塞调用它的线程。因此可以看到runBlocking的相关日志输出的位置是不会变化的。这就是说runBlocking会阻塞调用它的线程,直到runBlocking运行结束才能继续执行下去。

        我们看到后面四条日志是无序的,但是launchJob始终在asyncJob前面。而launch和async协程体内的日志输出是无序的。每执行一次看到的顺序都有可能跟之前的不一样。我们前面提到过launch和async都是启动一个协程但不会阻塞调用线程,所以launchJob始终在asyncJob前面。

runBlocking的返回值

        由上述的日志可以看到runBlockingJob的输出结果为41,为什么是41呢?其他的默认返回值一个协程作业的当前状态。

截屏2023-07-29 17.45.22.png

最后的返回值是调用了coroutine.joinBlocking()方法。

截屏2023-07-29 17.46.28.png

coroutine.joinBlocking()方法将state 强转为了范型T。

runBlocking它的设计目的就是将常规的阻塞代码连接到一起,主要用于main函数和测试中。

launch函数

上述日志看到launchJob输出的是一个standaLoneCoroutine对象,不是说输出是一个job吗?

截屏2023-07-29 17.54.55.png

 可以看到launch方法最终返回的是coroutine对象,最后返回的是standaLoneCoroutine对象,其实standaLoneCoroutine对象就是一个job。

截屏2023-07-29 18.00.09.png

 

async 函数

asyncJob返回的是DeferredCoroutine对象

截屏2023-07-29 18.03.33.png

asyncJob返回 DeferredCoroutine不仅继承AbstractCoroutine<T>,同样也继承Deferred<T>接口。那么DeferredCoroutine就是一个Deferred<T>,一个携带返回值的job。 

截屏2023-07-29 18.04.54.png

 我们一开始需要关注的Deferredawait()方法,可以通过返回的Deferred对象,调用await()方法来获取返回值。

public suspend fun awiat(): T

挂起函数

suspend是协程的关键字,表示是一个挂起函数,每一个被suspend修饰的方法只能在suspend方法或者协程中调用。

private fun start(){
    GlobalScope.launch{
        val launchJob = launch{
            Log.d("launch", "启动一个协程")
        }
        Log.d("launchJob", "$launchJob")
        val asyncJob = async{
            Log.d("async", "启动一个协程")
            "我是async返回值"
        }
        Log.d("asyncJob.await", ":${asyncJob.await()}")
        Log.d("asyncJob", "$asyncJob")
    }
}

输出:

D/launchJob: StandaloneCoroutine{Active}@f3d8da3
D/launch: 启动一个协程
D/async: 启动一个协程
D/asyncJob.await:我是async返回值
D/asyncJob: DeferredCoroutine{Completed}@d6f28a0

或者

D/launchJob: StandaloneCoroutine{Active}@f3d8da3
D/async: 启动一个协程
D/launch: 启动一个协程
D/asyncJob.await: :我是async返回值
D/asyncJob: DeferredCoroutine{Completed}@d6f28a0

可以看到asyncJob.await()输出的是我们之前定义好的返回值,同时DeferredCoroutine的状态变成了{Completed}。这是因为await()是在不阻塞线程的情况下等待该值完成并继续执行,当Deferred计算完成后返回结果值,或者deferred被取消,则抛出响应的异常CancellationException。但是又因为await()是挂起函数。他会挂起调用它的协程。因此我们看到Deferred的状态是{Completed}。同时输出的await()日志也在后面。

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

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

相关文章

湘大oj1088 N!:求阶乘 数据太大怎么处理 常规的递归求阶乘

一、链接 N&#xff01; 二、题目 Description 请求N&#xff01;&#xff08;N<10000&#xff09;&#xff0c;输出结果对10007取余 输入 每行一个整数n&#xff0c;遇到-1结束。 输出 每行一个整数&#xff0c;为对应n的运算结果。 Sample Input 1 2 -1 Sample Outp…

【数据结构与算法】左叶子之和

左叶子之和 递归三部曲 确定递归函数的参数和返回值 int sumOfLeftLeaves(TreeNode* root)确定终止条件 遍历遇到空节点 if (root NULL) return 0;单层的递归逻辑 遍历顺序&#xff1a;左右中&#xff08;后序遍历&#xff09; 选择后序遍历的原因&#xff1a;要通过递归函…

【Linux操作系统】深入了解系统编程gdb调试工具

在软件开发过程中&#xff0c;调试是一个非常重要的步骤。无论是在开发新的软件还是维护现有的代码&#xff0c;调试都是解决问题的关键。对于Linux开发者来说&#xff0c;GDB是一个非常有用的调试工具。在本文中&#xff0c;我们将探讨Linux中使用GDB进行调试的方法和技巧。 …

C# OpenCvSharp 读取rtsp流

效果 项目 代码 using OpenCvSharp; using OpenCvSharp.Extensions; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using Syste…

HTTPS安全通信

HTTPS,TLS/SSL Hyper Text Transfer Protocol over Secure Socket Layer,安全的超文本传输协议,网景公式设计了SSL(Secure Sockets Layer)协议用于对Http协议传输的数据进行加密,保证会话过程中的安全性。 使用TCP端口默认为443 TLS:(Transport Layer Security,传输层…

30、Flink SQL之SQL 客户端(通过kafka和filesystem的例子介绍了配置文件使用-表、视图等)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

【移动机器人运动规划】03 —— 基于运动学、动力学约束的路径规划

文章目录 前言相关代码整理:相关文章&#xff1a; 介绍什么是kinodynamic&#xff1f;为什么需要kinodynamic&#xff1f;模型示例unicycle model&#xff08;独轮车模型&#xff09;differential model&#xff08;两轮差速模型&#xff09;Simplified car model (简化车辆模型…

YOLO相关原理(文件结构、视频检测等)

超参数进化(hyperparameter evolution) 超参数进化是一种使用了genetic algorithm&#xff08;GA&#xff09;遗传算法进行超参数优化的一种方法。 YOLOv5的文件结构 images文件夹内的文件和labels中的文件存在一一对应关系 激活函数&#xff1a;非线性处理单元 activation f…

WWW 23 | Facebook Marketplace的意图理解:用双塔模型处理结构化的产品目录

©PaperWeekly 原创 作者 | 何允中 单位 | Meta 研究方向 | Information Retrieval 摘要 本文介绍了 Facebook Marketplace 团队提出的 HierCat 构架&#xff0c;以解决电商搜索中的意图理解难题。HierCat 利用线上产品交互挖掘弱监督数据&#xff0c;并通过基于 Transfor…

sqlserver 数据库显示 正在还原

问题描述之前不太会搞差异备份的恢复&#xff0c;然后恢复发生了失败之后这个数据库一直处于(正在还原……状态 并且出现数据库无法访问的情况 尝试解决1执行查询Restore Database 数据库名称 with Recovery然后不太能行 2执行查询Restore Database 数据库名称 with NoRecovery…

10个最流行的免费3D模型下载网站

作为一名独立游戏开发者&#xff0c;自己创建图形、配乐、动画和更多东西是相当具有挑战性的。 创建资产所需的成本和时间有时是许多游戏开发商无法承受的。 这就是他们选择在互联网上搜索免费内容的原因。 现在&#xff0c;在浩瀚的内容海洋中获得如此免费的东西有点困难。 本…

uniapp 微信小程序 使用高德地图 定制气泡

前言 我们常说的uniapp或者原生微信小程序框架使用高德地图&#xff0c;并不是ui就是高德地图&#xff0c;而是api用的高德地图&#xff0c;ui仍然是框架内置的地图&#xff0c;也就是说&#xff0c;地图和api是分开&#xff0c;微信小程序的内置地图自然是腾讯地图。 高德地…

SpringBoot第34讲:SpringBoot集成ShardingJDBC - 基于JPA的DB隔离多租户方案

SpringBoot第34讲&#xff1a;SpringBoot集成ShardingJDBC - 基于JPA的DB隔离多租户方案 本文是SpringBoot第34讲&#xff0c;主要介绍ShardingJDBC的分片算法和分片策略&#xff0c;并在此基础上通过SpringBoot集成ShardingJDBC的几种策略&#xff08;标准分片策略&#xff0c…

DevOps最佳实践和工具在本地环境中的概述

引言 最近&#xff0c;我进行了一次网上搜索&#xff0c;以寻找DevOps的概述&#xff0c;尽管有大量的DevOps工具和实践&#xff0c;但我无法找到一个综合的概述。因此&#xff0c;我开始了对DevOps生态系统和最佳实践的梳理&#xff0c;以创建一个整体视图,方便后续研究实践 C…

Fabric系列 - 知识点整理

知识点 源码编译 主机编译 容器编译 手动部署(docker-compose) 单peer 多peer 中途加peer 多主机多peer 链码 语法, 接口 (go版) 命令行调用 ca server 在DApp中使用SDK调用 (js版) 部署的几个阶段 部署1排序和1节点, 1组织1通道 光部署能Dapp 带ca server (每个组织一个)…

SQL SERVER 2019 数据库还原测试库的方法

1、备份正式库数据 2、在其它电脑上还原备份的数据库 不需要覆盖其它数据库&#xff0c;直接还原出数据库 还原时修改文件名和数据库名称&#xff1a; 修改文件名称 还原成功

【数学建模】--时间序列分析

时间序列分析概念与时间序列分解模型 定义&#xff1a;时间序列也称动态序列&#xff0c;是指将某种现象的指标数值按照时间顺序排列而成的数值序列。时间序列分析大致可分成三大部分&#xff0c;分别是描述过去&#xff0c;分线规律和预测未来&#xff0c;本讲将主要介绍时间序…

心理咨询预约管理系统javaweb医院挂号jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 心理咨询预约管理系统javaweb MVC模式&#xff0c;普…

PCIe VSC、VSEC、DVSEC

&#x1f525;点击查看精选 PCIe 系列文章&#x1f525; &#x1f525;点击进入【芯片设计验证】社区&#xff0c;查看更多精彩内容&#x1f525; &#x1f4e2; 声明&#xff1a; &#x1f96d; 作者主页&#xff1a;【MangoPapa的CSDN主页】。⚠️ 本文首发于CSDN&#xff0…

[LeetCode - Python] 11.乘最多水的容器(Medium);26. 删除有序数组中的重复项(Easy)

1.题目&#xff1a; 11.乘最多水的容器&#xff08;Medium&#xff09; 1.代码 1.普通双指针对撞 贪心算法 class Solution:def maxArea(self, height: List[int]) -> int:# 对撞双指针# 对比记录最大面积&#xff0c;并移动短板&#xff0c;重新计算&#xff1b;left,…