Kotlin并发请求的一些知识记录

    private suspend fun fetchDataConcurrently(list: MutableList<MyType>,onRequestResult: (Int, List<MyType>?) -> Unit	//高阶函数回调) {val deferredList = mutableListOf<Deferred<MyType?>>()// 设定任务超时时间为12秒,并使用 async 并发执行请求withTimeoutOrNull(12_000L) {Log.d(TAG, "request size:${list.size}")for ((index, item) in list.withIndex()) {val deferred = async {	//对每个item都发起一次异步请求, 这里是并发的请求//通过callbackChannel来传递结果,参数UNLIMITED为无限缓冲,具体的在下面扩展有讲val callbackChannel = Channel<MyType?>(Channel.UNLIMITED)SDKInstance(item.id,object : SDKCallback() {override fun onSuccess(children: List<SDKType>,) {super.onSuccess(children)Log.d(TAG, "success name: ${item.name}")val item = MyType(item.name, item.id)item.list = childrencallbackChannel.trySend(item).isSuccess}override fun onError() {super.onError()callbackChannel.trySend(null).isFailureLog.d(TAG, "error name: ${item.name}")}})callbackChannel.receive()}deferredList.add(deferred)}}// 等待所有请求完成val resultData = mutableListOf<MyType>()var requestSituation: Int = REQUEST_TIME_DEFAULT	//超时情况记录for (deferred in deferredList) {try {val result = deferred.await()	//这里的await就是等待异步任务完成result?.let {resultData.add(it)requestSituation = REQUEST_TIME_NORMAL}} catch (e: Exception) {// 处理任务异常Log.d(TAG, "error: ${e}, isTimeOut = $requestSituation")if (requestSituation != REQUEST_TIME_NORMAL) { //如果有数据返回成功就无需记录超时requestSituation = REQUEST_TIME_TIMEOUT	//如果所有数据获取超时,需要反馈异常}}}Log.d(TAG, "response size: ${resultData.size}")if(requestSituation == REQUEST_TIME_TIMEOUT) {onRequestResult(REQ_ERROR, null)} else if (resultData.isEmpty()) {onRequestResult(REQ_NO_DATA, null)} else {if (list.size - resultData.size > Math.max((list.size - 1) / 2, 1) && resultData.size < 5) {onRequestResult(REQ_ERROR, null)} else {onRequestResult(REQ_SUCCESS, resultData)myData.applyPut { cache ->cache[MyKey] = resultData	//这里使用了LruCache,以后再讲}}}}

扩展:

Channel在这段代码中的作用

  1. 桥接api与协程:将传统的回调式API(SDK的回调)转换为协程友好的异步操作
  2. 同步时序:确保在SDK回调后,协程能够继续执行
  3. 结果传递:将回调结果传递回主协程流程

潜在问题

  1. 使用无限缓冲可能不必要,因为channel开启在for循环中,一次只需要接收一个结果
  2. channel没有被显式关闭,可能导致资源泄漏
try{
//回调处理
...
}	finally {callbackChannel.close()	//确保关闭
}

Channel是什么?

它是Kotlin协程中的一个并发通信原语,用于在不同协程之间安全的传递数据。类似阻塞队列,但完全基于协程的非阻塞特性实现。
它是协程间通信的强大工具,特别适合将回调式API转换为挂起函数,使异步代码更线性易读。

Channel的基本特点

生产者-消费者模式:一个协程发送数据,另一个协程接收数据
线程安全:内部已处理好线程同步的问题
可挂起:当Channel满或空时,发生和接收操作会挂起协程而非阻塞线程

Channel在以上代码中的时序关系

  1. 创建channel:在每次async任务中创建一个channel

  2. SDK回调:当收到SDK回调,成功获取数据时,使用trySend发送数据,失败时使用trySend发送null

  3. 接收结果:通过callbackChannel.receive()等待SDK回调

    关键时序点:receive会挂起协程,直到SDK回调触发并发送数据到Channel

Channel的常见用法

  1. 创建Channel
//创建有缓冲的Channel
val channel = Channel<T>(capacity)//capacity
//RENDEZVOUS(默认,无缓冲)
//UNLIMITED(无限缓冲,MAX_VALUE)
//CONFLATED(只保留最小值)
//具体数字(固定缓冲大小)
  1. 发送数据
//常规发送(可能挂起)
channel.send(data)//尝试发送(不挂起)
channel.trySend(data).isSuccess
  1. 接收数据
//常规接收(可能挂起)
val data = channel.receive()//尝试接收(不挂起)
val data = channel.tryReceive().getOrNull()
  1. 关闭Channel
channel.close()	//发送结束信号, 防止资源泄漏

关于这段代码的优化写法

private suspend fun fetchDataConcurrently(list: MutableList<MyType>,onRequestResult: (Int, List<MyType>?) -> Unit
) {val resultData = mutableListOf<MyType>()var requestSituation = REQUEST_TIME_DEFAULTtry {withTimeout(12_000L) {val deferredResults = list.map { item ->async {try {val result = suspendCancellableCoroutine<MyType?> { continuation ->val callback = object : SDKCallback() {override fun onSuccess(children: List<SDKType>,) {val item= MyType(item.name, item.id).apply {list = children}continuation.resume(item)}override fun onError() {continuation.resume(null)}}continuation.invokeOnCancellation {// 如果协程被取消,可以在这里取消SDK请求// 需要SDK支持取消操作}SDKInstance(item.id, callback)}result} catch (e: Exception) {null}}}deferredResults.forEach { deferred ->deferred.await()?.let {resultData.add(it)requestSituation = REQUEST_TIME_NORMAL}}}} catch (e: TimeoutCancellationException) {if (requestSituation != REQUEST_TIME_NORMAL) {requestSituation = REQUEST_TIME_TIMEOUT}Log.w(TAG, "Request timeout: ${e.message}")} catch (e: Exception) {Log.e(TAG, "Unexpected error: ${e.message}", e)}// 结果处理逻辑保持不变when {requestSituation == REQUEST_TIME_TIMEOUT -> {onRequestResult(REQ_ERROR, null)}resultData.isEmpty() -> {onRequestResult(REQ_NO_DATA, null)}list.size - resultData.size > maxOf(list.size / 2, 1) && resultData.size < 5 -> {onRequestResult(REQ_ERROR, null)}else -> {onRequestResult(REQ_SUCCESS, resultData)myData.applyPut { cache ->cache[myKey] = resultData}}}
}

优化点说明

  • 替换Channel为suspendCancellableCoroutine:

    更直接地将回调API转换为挂起函数

    避免了Channel资源管理问题

  • 改进资源管理:

    使用invokeOnCancellation处理协程取消

    确保所有可能的异常都被捕获

  • 缓冲策略优化:

    完全移除了不必要的Channel缓冲

    使用更直接的协程控制流

  • 错误处理增强:

    明确区分超时和其他异常

    更好的日志记录

核心知识点

  1. 协程与回调的转换:

    suspendCancellableCoroutine将回调API转换为挂起函数协程取消处理机制
    
  2. 结构化并发:

    withTimeout创建有时间限制的作用域async/await并发模式
    
  3. 资源管理:

    协程取消时的清理工作异常处理边界
    
  4. 并发控制:

    多个请求的并行执行结果的聚合处理
    
  5. 状态管理:

    请求状态的跟踪(REQUEST_TIME_NORMAL/TIMEOUT)结果的成功/失败判定逻辑
    

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

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

相关文章

配置VScodePython环境Python was not found;

Python was not found; run without arguments to install from the Microsoft Store, or disable this shortcut from Settings > Manage App Execution Aliases. 候试试重启电脑。 在卸载重装python后会出现难以解决的局面&#xff0c;系统变量&#xff0c;命令行&#…

OracleLinux7.9-ssh问题

有套rac环境&#xff0c;db1主机无法ssh db1和db1-priv&#xff0c;可以ssh登录 db2和db2-priv [rootdb1 ~]# ssh db1 ^C [rootdb1 ~]# ssh db2 Last login: Wed May 14 18:25:19 2025 from db2 [rootdb2 ~]# ssh db2 Last login: Wed May 14 18:25:35 2025 from db1 [rootdb2…

如何创建maven项目

1.IDEA 中创建 Maven 项目 步骤一&#xff1a;点击 File -> New -> Project&#xff0c;在弹出的窗口左侧选择 Maven&#xff0c;点击 Next&#xff1a; 步骤二&#xff1a;填写项目的 GroupId、ArtifactId、Version 等信息&#xff08;这些对应 pom.xml 中的关键配置&am…

Python爬虫实战:研究ajax异步渲染加密

一、引言 在当今数字化时代,数据已成为推动各行业发展的核心驱动力。网络爬虫作为一种高效的数据采集工具,能够从互联网上自动获取大量有价值的信息。然而,随着 Web 技术的不断发展,越来越多的网站采用了 AJAX(Asynchronous JavaScript and XML)异步渲染技术来提升用户体…

沪深股指期货指数怎么参考交易?

沪深股指期货指数&#xff0c;其实它就是咱们炒股时的一个“风向标”和“工具箱”。今天咱们就来聊聊怎么参考这个指数来交易&#xff0c;让你也能轻松上手&#xff01; 一、沪深股指期货指数是啥&#xff1f; 沪深股指期货指数&#xff0c;简单来说&#xff0c;就是基于沪深…

演员评论家算法

一、演员评论家算法核心思想和原理 演员(actor)代表策略&#xff0c;评论家代表价值函数。演员评论家算法是基于价值和策略的综合性方法。具体来说该算法使用了策略梯度和时序差分方法&#xff0c;是二者的一种有机结合。 1. 主要思想 策略梯度算法以轨迹为单位更新&#xf…

PyCharm 快捷键指南

PyCharm 快捷键指南 常用编辑快捷键 代码完成&#xff1a;Ctrl Space 提供基本的代码完成选项&#xff08;类、方法、属性&#xff09;导入类&#xff1a;Ctrl Alt Space 快速导入所需类语句完成&#xff1a;Ctrl Shift Enter 自动结束代码&#xff08;如添加分号&#…

计算图存储采用矩阵吗,和张量关系

计算图存储采用矩阵吗,和张量关系 计算图的存储方式与张量的关系 一、计算图的存储方式 计算图(Computational Graph)是一种用于描述数学运算的有向无环图(DAG),其节点代表运算(如加减乘除、矩阵乘法、激活函数等),边代表运算的输入和输出(通常是张量)。计算图的…

RDD中分区、分区器及自定义分区器的学习

深入理解 Spark 中 RDD 分区与分区器&#xff1a;原理、应用及自定义实现 在大数据处理领域&#xff0c;Apache Spark 凭借其高效的分布式计算能力成为了众多开发者的首选框架。在 Spark 中&#xff0c;弹性分布式数据集&#xff08;Resilient Distributed Dataset&#xff0c…

OpenCV CUDA 模块中用于在 GPU 上计算矩阵中每个元素的绝对值或复数的模函数abs()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 void cv::cuda::abs(InputArray src, OutputArray dst, Stream &stream Stream::Null()) 是 OpenCV 的 CUDA 模块中的一个函数&#xff0c;…

FramePack - 开源 AI 视频生成工具

&#x1f3ac; 项目简介 由开发者 lllyasviel 创建的一个轻量级动画帧处理工具库&#xff0c;专门用于游戏开发、动画制作和视频处理中的帧序列打包与管理。该项目采用高效的算法实现&#xff0c;能够显著提升动画资源的处理效率。 此 AI 视频生成项目&#xff0c;旨在通过低显…

商业架构 2.0 时代:ZKmall开源商城前瞻性设计如何让 B2B2C 平台领先同行 10 年?

在数字化转型加速的今天&#xff0c;传统 B2B2C 平台面临用户体验割裂、数据孤岛严重、业务扩展困难等挑战。ZKmall 开源商城通过 “业务中台 数据中台 技术中台”的三位一体架构设计&#xff0c;结合“插件化扩展 分布式服务 智能决策”*三大核心能力&#xff0c;构建起具…

Java中Money类的使用及与BigDecimal的对比

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 一、为什么需要Money类&#xff1f; 在金融和商业计算中&#xff0c;精确的货币处理是至关重要的。虽然Java提供了BigDecimal类来处理高精度计算&#xff0c…

判断数据的所有属性是否都是基本类型

方法解释 OnlyPrimitiveTypes 方法: 参数: 接收一个对象 obj 进行检查。返回值: 返回布尔值&#xff0c;表示对象及其所有属性是否仅包含基本类型。逻辑: 首先检查 obj 是否为 null&#xff0c;如果是&#xff0c;则返回 true。然后检查 obj 的类型是否为基本类型&#xff0c;如…

【Linux】Linux安装并配置mysql

目录 1.删除原有mysql 2.添加 MySQL Yum Repository 3.安装 MySQL 3.1.报错 4.启动 MySQL 服务 5.设置mysql 5.1.密码验证组件 5.2.密码策略 5.3.移除匿名用户 5.4.是否禁用root远程访问 5.5.是否删除test 5.6.是否重新加载权限 5.7.设置远程权限 5.7.1.登录mysql…

springboot AOP 接口限流(基于IP的接口限流和黑白名单)

使用 Spring Boot 自定义注解和AOP实现基于IP的接口限流和黑白名单 在我们日常开发的项目中为了保证系统的稳定性&#xff0c;很多时候我们需要对系统做限流处理&#xff0c;它可以有效防止恶意请求对系统造成过载。常见的限流方案主要有&#xff1a; 网关限流&#xff1a; NG…

OpenCV CUDA模块中矩阵操作------范数(Norm)相关函数

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 OpenCV 的 CUDA 模块中&#xff0c;与范数&#xff08;Norm&#xff09;相关的函数主要用于计算矩阵的范数或者两个矩阵之间的差值范数。 主…

生成对抗网络(Generative Adversarial Networks ,GAN)

生成对抗网络是深度学习领域最具革命性的生成模型之一。 一 GAN框架 1.1组成 构造生成器&#xff08;G&#xff09;与判别器&#xff08;D&#xff09;进行动态对抗&#xff0c;实现数据的无监督生成。 G&#xff08;造假者&#xff09;&#xff1a;接收噪声 ​&#xff0c…

httpclient请求出现403

问题 httpclient请求对方服务器报403&#xff0c;用postman是可以的 解决方案: request.setHeader( “User-Agent” ,“Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0” ); // 设置请求头 原因&#xff1a; 因为没有设置为浏览器形式&#…

嵌入式硬件篇---IIC

文章目录 前言1. IC协议基础1.1 物理层特性两根信号线SCLSDA支持多主多从 标准模式电平 1.2 通信流程起始条件&#xff08;Start Condition&#xff09;从机地址&#xff08;Slave Address&#xff09;应答&#xff08;ACK/NACK&#xff09;数据传输&#xff1a;停止条件&#…