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.pswp.cn/bicheng/81216.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/81216.shtml
英文地址,請注明出處:http://en.pswp.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;停止條件&#…