Kotlin 同步与异步执行:run、runCatching、runBlocking 与 runInterruptible

前言 

        首先,run 和 runCatching 是同步的,而 runBlocking 和 runInterruptible 是异步的。 

    run 和 runCatching 是 Kotlin 标准库的一部分,可以在所有支持的平台上使用。 runBlocking 和 runInterruptible 是 Coroutines 的一部分。


 一、run

        run 是一个作用域函数。可以在一个对象上调用它,代码块会直接访问对象的属性和方法,而不需要 this (但你也可以使用 this)。另外, run 可以返回一个结果,这个结果可以在后续的步骤中使用。 

val event = Event(id = UUID.randomUUID(),value = 10,message = null)val isEven = event.run {value % 2 == 0}println("Is Event.value even? $isEven.")

打印结果:Is Event.value even? true. 

也可以在run的作用域代码块中修改message的值。

run 和 apply 有什么区别呢?好吧,主要的区别在于他们的返回值

run 是灵活的。它可以返回任何类型,不仅仅是它被调用的对象的类型。另一方面, apply 总是返回对象本身,这对于链式对象配置非常好。

此外,如前所述, run 可以独立于对象运行。 apply 总是需要一个对象来工作。        


二、runCatching

        它是 run 的一个变体。 runCatching 实际上是一个 try...catch 块。

        但有一个重要的区别。它将块执行的结果封装到一个 Result 对象中。另一个优点是 runCatching 块执行的结果可以被比较。

val event = Event(id = UUID.randomUUID(),value = 10,message = null,badModifyablePropertyForDemoPurposes = "Some string")val result = event.runCatching {value / 0  //错误代码
}.onFailure {println("We failed to divide by zero. Throwable: $it")
}.onSuccess {println("Devision result is $it")
}println("Returned value is $result")

打印结果:

 I  We failed to divide by zero. Throwable:java.lang.ArithmeticException: divide by zeroI  Returned value is: Failure(java.lang.ArithmeticException: divide by zero)

所以,正如你所看到的,使用 runCatching 提供了几个优势。块执行的失败或成功的结果可以用链式的处理,还可以拿到这个错误的变量在流中抛出。


        异步的 runBlocking 和 runInterruptable与run和runcatching的唯一共同点是都能够执行一段代码块。然而,它们显著的区别在于功能和用例方面。

三、 runBlocking

主要用例:

  1. 1. 当需要在一些测试中阻塞直到协程完成执行的时候。

  2. 2. 为了执行一些顶级的代码(也就是说,不能在协程中运行的代码)。

主要的问题是,为什么只有这些呢?

为什么我在 StackOverflow 上看到的回答中,比如说,需要避免使用这个函数?是的,它阻塞了当前的线程,但我们可以产生自己的线程,这样就不会影响其他的代码。

现在,让我们看一下使用 viewModel 的更现实的场景。

class MainViewModel : ViewModel() {fun runFlows() {thread(name = "Manual Thread",) {println("Thread: ${Thread.currentThread()}")runCollection()}}private suspend fun collect(action: (Int) -> Unit) {runBlocking {val eventGenerator = EventGenerator()eventGenerator.coldFlow.collect {action(it)}}}private fun runCollection() {viewModelScope.launch {collect {println("Collection in runCollections #1: $it: ${Thread.currentThread()}")}}viewModelScope.launch {collect {println("Collection in runCollections #2: $it: ${Thread.currentThread()}")}}}
}

打印结果: 

00:40:44.332  I  Emitting 0
00:40:44.334  I  Collection in runCollections #1: 0: Thread[main,5,main]
00:40:45.336  I  Emitting 1
00:40:45.336  I  Collection in runCollections #1: 1: Thread[main,5,main]
00:40:46.337  I  Emitting 2
00:40:46.338  I  Collection in runCollections #1: 2: Thread[main,5,main]

请注意,生成线程不会提供任何内容,它只是生成一个根本不影响异步操作的线程。 viewModelScope 绑定到主调度程序,最终进入主线程(当然,这是一个简化的解释,因为深入研究了调度程序的细节以及 Main 之间的区别、Main.immediate 不在本文中)。

如果 runBlocking 从 collect() 实现中删除,则调用 runFlows() 打印

01:05:48.180  I  Emitting 0
01:05:48.181  I  Collection in runCollections #1: 0: Thread[main,5,main]
01:05:48.181  I  Emitting 0
01:05:48.181  I  Collection in runCollections #2: 0: Thread[main,5,main]
01:05:49.182  I  Emitting 1
01:05:49.182  I  Collection in runCollections #1: 1: Thread[main,5,main]
01:05:49.183  I  Emitting 1
01:05:49.183  I  Collection in runCollections #2: 1: Thread[main,5,main]

这就是我们通常期望的异步操作。是的,这是预料之中的,但如果您不牢记 viewModelScope 的绑定内容,则并不明显。

将 thread 移动到 collect() 函数

private suspend fun collect(action: (Int) -> Unit) {thread(name = "Manual Thread",) {runBlocking {val eventGenerator = EventGenerator()eventGenerator.coldFlow.collect {action(it)}}}}

也给出了类似的结果:

01:08:51.944  I  Emitting 0
01:08:51.944  I  Emitting 0
01:08:51.946  I  Collection in runCollections #2: 0: Thread[Manual Thread,5,main]
01:08:51.947  I  Collection in runCollections #1: 0: Thread[Manual Thread,5,main]
01:08:52.948  I  Emitting 1
01:08:52.948  I  Emitting 1
01:08:52.948  I  Collection in runCollections #1: 1: Thread[Manual Thread,5,main]
01:08:52.948  I  Collection in runCollections #2: 1: Thread[Manual Thread,5,main]

使用 runBlocking 很容易失去对异步操作的跟踪,并失去用于自动管理挂起和切换要执行的协程的强大协程功能。如果您不是 Java 和 Android 线程方面的专家,并且由于某种原因协程实现不符合您的需求,那么这不是最好的异步方案。感觉在移动应用程序开发中它应该主要用于测试。


 四、runInterruptible

        文档指出将可中断的方式调用代码块。此函数不会生成线程并遵循您作为参数提供的调度程序。

在 viewModel 中添加了新方法。

fun runInterruptible() {viewModelScope.launch {println("Start")kotlin.runCatching {withTimeout(100) {runInterruptible(Dispatchers.IO) {interruptibleBlockingCall()}}}.onFailure {println("Caught exception: $it")}println("End")}
}private fun interruptibleBlockingCall() {Thread.sleep(3000)
}

打印日志: 

 I  StartI  Caught exception: kotlinx.coroutines.TimeoutCancellationException:Timed out waiting for 100 msI  End

注意调用链。 runCatching (try…catch )然后是 withTimeout 。 

withTimeout 抛出异常,但没有看到它的日志。如果我添加 try…catch 或 runCatching 那么可以检测到异常,没有它协程就默默地停止工作了。

没有找到这种行为的原因,并且在跟踪器中没有看到任何报告。因此请记住使用 try…catch 或 withTimeoutOrNull 。

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

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

相关文章

使用 crypto-js 进行 AES 加解密操作

在前端开发中,数据的加密和解密是为了保障用户隐私和数据的安全性而常见的任务。AES(Advanced Encryption Standard)是一种对称密钥加密算法,被广泛用于保护敏感信息的传输和存储。本文将介绍 AES 加解密的基本原理,并…

寒假思维训练计划day11

每日一题,这两天有事,断更了一天,今天补上,感觉状态也不太好,来道1500的题压压惊。 宣传一下我总结的几个构造题模型,一点个人的浅薄见解: 1、前后缀贪心,比如说观察前后缀的sum&…

解决el-radio-group只触发一次的问题

1.需求是点击合并后&#xff0c;出来二次确认框。现在的问题是点击完出现二次确认框后&#xff0c;再次点击不出来二次确认框了 2.一开始代码是这样写的 <el-radio-group v-model"unfold" size"mini" changechangeMerge><el-radio-button :labe…

RK3568平台 LT9211转接芯片调试笔记

一.简介 龙讯LT9211是一个高性能转换器&#xff0c;支持MIPI LVDS TTL两两之间转换。 使用此款芯片大部分为MIPI与LVDS进行互相转换。 下图为LT9211的典型应用图&#xff1a; 二.LT9211原理图 三.车载显示器和摄像头系统 四.调试LT9211输出 MIPI数据 &#xff08;1&#xf…

web系统设计安全性基本要求

接口设计安全 身份鉴别 独立的登录模块&#xff1a;为社会用户和平台运营管理用户提供独立的登录地址、登录界面和身份认证模块&#xff0c;通过防火墙等设备严格限制能够登录WEB应用的用户地址、身份&#xff1b; 双因素认证&#xff1a; 平台运营管理人员&#xff1a;采用用…

Civil 3D安装教程,免费使用,带安装包和工具,一分钟轻松搞的安装

前言 Civil 3D是一款面向基础设施行业的建筑信息模型&#xff08;BIM&#xff09;解决方案。它为基础设施行业的各类技术人员提供了强大的设计、分析以及文档编制功能&#xff0c;广泛适用于勘察测绘、岩土工程、交通运输、水利水电、市政给排水、城市规划和总图设计等众多领域…

MySQL(五)——多表查询

上期文章 MySQL&#xff08;四&#xff09;——约束 文章目录 上期文章多表关系一对多&#xff08;多对一&#xff09;多对多多表外键关系可视化一对一 多表查询概述笛卡尔积多表查询分类连接查询 内连接隐式内连接显式内连接 外连接左外连接右外连接 自连接联合查询 union&am…

Android Framework | AOSP源码下载及编译指南(基于Android13)

Android Framework | AOSP源码下载及编译指南(基于Android13) 引言 AOSP&#xff08;Android Open Source Project&#xff09;是Android操作系统的开源项目&#xff0c;通过下载和编译AOSP源码&#xff0c;您可以获得原始的Android系统&#xff0c;并进行定制和开发。本教程…

【C++】—— C++的IO流

在C中&#xff0c;I/O流是一项关键的编程概念&#xff0c;为程序提供了与外部世界进行交互的重要手段。通过使用C的强大I/O库&#xff0c;开发者能够实现对标准输入输出、文件、字符串等多种数据源的高效处理。接下来让我们深入探讨C的I/O流&#xff0c;了解其基本原理、常见操…

代码随想录算法训练营day25 || 216.组合总和III,17.电话号码的字母组合

视频讲解&#xff1a; 还得用回溯算法&#xff01;| LeetCode&#xff1a;17.电话号码的字母组合_哔哩哔哩_bilibili 和组合问题有啥区别&#xff1f;回溯算法如何剪枝&#xff1f;| LeetCode&#xff1a;216.组合总和III_哔哩哔哩_bilibili 216.组合总和III 思路&#xff1a;…

浏览器插件:WebScraper基本用法和抓取页面内容(不会编程也能爬取数据)

Web Scraper 是一个浏览器扩展&#xff0c;用于从页面中提取数据(网页爬虫)。对于简单或偶然的需求非常有用&#xff0c;例如正在写代码缺少一些示例数据&#xff0c;使用此插件可以很快从类似的网站提取内容作为模拟数据。从 Chrome 的插件市场安装后&#xff0c;页面 F12 打开…

RT-Thread experimental 代码学习(1)thread_sample

RTOS的最基础功能是线程。 线程的调度是如何工作的&#xff1f;RT-thread官方的实验文档是最好的参考。 老规矩&#xff0c;先放法国人doxygen。 thread_sample 代码的调用关系图 有意思的是&#xff0c;RT有两种创建线程的方式 - 静态和动态&#xff0c;粗略的理解是&…

微信小程序之WXML 模板语法之数据绑定、事件绑定、wx:if和列表渲染

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

数字图像处理期末速成笔记

目录 一、基础知识二、相邻像素间基本关系三、图像增强方法1、直方图求解2、直方图均衡化3、直方图规定化4、图像平滑5、邻域平均法&#xff08;线性&#xff09;6、 中值滤波法&#xff08;分线性&#xff09;7、中值滤波与领域平均的异同8、4-邻域平滑法9、超限像素平滑法10、…

我们应该了解的⽤户画像

当我们谈⽤户画像时&#xff0c;到底在谈什么 对于互联⽹公司来说&#xff0c;企业的增⻓、内容、活动、产品等⼯作基本上都是围绕着“⽤户”来做的&#xff0c;可以说都是在做“⽤户运营”这个⼯作&#xff0c;⽽⽤户画像是⽤户运营⼯作中⾮常重要的⼀环 ⽤户画像的主要特征是…

【js】js 异步机制详解 Generator / Async / Promise

三种语法功能放在一起&#xff0c;是因为他们都有相似特点&#xff1a; 维护某种状态在未来恢复状态并执行 本文重点回答以下几个问题&#xff1a; 为什么 Generator 和 Async 函数的 代码执行流 都可以简化成树形结构&#xff1f;async 函数为什么返回一个 promise&#xf…

Cloudreve存储策略-通过从机存储来拓展容量

Sham的云服务器是搬瓦工最低低低配的&#xff0c;1H 0.5G不说&#xff0c;硬盘容量也只有10g&#xff0c;说实话&#xff0c;装了宝塔面板和服务器套件后&#xff0c;基本满了&#xff0c;这时又想在云服务器上打个网盘用于下载、存储&#xff0c;这时就需要拓展硬盘&#xff0…

【podman】podman学习

Podman 官网 快速开始 面向 Docker 用户的 Podman 和 Buildah Podman是一个开源的容器、pod和容器映像管理引擎。Podman使查找、运行、构建和共享容器变得容易。 Podman Desktop是Podman的图形应用程序&#xff0c;使其易于在Windows、MacOS和Linux上安装和使用Podman&…

烟火检测AI边缘计算智能分析网关V4如何通过ssh进行服务器远程运维

智能分析网关V4是一款高性能、低功耗的AI边缘计算硬件设备&#xff0c;它采用了BM1684芯片&#xff0c;集成高性能8核ARM A53&#xff0c;主频高达2.3GHz&#xff0c;并且INT8峰值算力高达17.6Tops&#xff0c;FB32高精度算力达到2.2T&#xff0c;每个摄像头可同时配置3种算法&…

npm, yarn和pnpm清理缓存

文章目录 前言npm查看缓存路径清理缓存 yarn查看缓存路径清理缓存 pnpm查看缓存路径清理缓存 前言 npm, yarn和pnpm是时下主流的node.js包管理器。 随着前端项目的增多&#xff0c;会下载许多的依赖。不管是哪种包管理器&#xff0c;都会使用缓存来增加下次下载的速度。但很多…