Răsfoiți Sursa

解决并发择快转换函数问题

drake 4 ani în urmă
părinte
comite
e321357ea7

+ 5 - 5
net/src/main/java/com/drake/net/transform/DeferredTransform.kt

@@ -19,11 +19,11 @@ package com.drake.net.transform
 import kotlinx.coroutines.Deferred
 
 
-fun <T> Deferred<T>.transform(block: (T) -> T): DeferredTransform<T> {
+fun <T, R> Deferred<T>.transform(block: (T) -> R): DeferredTransform<T, R> {
     return DeferredTransform(this, block)
 }
 
-data class DeferredTransform<T>(
-    val deferred: Deferred<T>,
-    val block: (T) -> T = { it }
-)
+data class DeferredTransform<T, R>(
+        val deferred: Deferred<T>,
+        val block: (T) -> R
+                                  )

+ 16 - 11
net/src/main/java/com/drake/net/utils/ScopeUtils.kt

@@ -159,19 +159,25 @@ inline fun <T> Flow<T>.scope(
  *
  * @param deferredArray 一系列并发任务
  */
+@OptIn(ExperimentalCoroutinesApi::class)
 @Suppress("SuspendFunctionOnCoroutineScope")
 suspend fun <T> CoroutineScope.fastest(vararg deferredArray: Deferred<T>): T {
     val chan = Channel<T>()
+    val mutex = Mutex()
     deferredArray.forEach {
-        launch {
+        launch(Dispatchers.IO) {
             try {
                 val result = it.await()
-                NetCancel.cancel(coroutineContext[CoroutineExceptionHandler])
-                chan.send(result)
+                mutex.withLock {
+                    NetCancel.cancel(coroutineContext[CoroutineExceptionHandler])
+                    chan.send(result)
+                }
             } catch (e: Exception) {
                 it.cancel()
                 val allFail = deferredArray.all { it.isCancelled }
-                if (allFail) throw e else e.printStackTrace()
+                if (allFail) throw e else {
+                    if (e !is CancellationException) e.printStackTrace()
+                }
             }
         }
     }
@@ -187,27 +193,26 @@ suspend fun <T> CoroutineScope.fastest(vararg deferredArray: Deferred<T>): T {
  */
 @OptIn(ExperimentalCoroutinesApi::class)
 @Suppress("SuspendFunctionOnCoroutineScope")
-suspend fun <T> CoroutineScope.fastest(vararg deferredArray: DeferredTransform<T>): T {
-    val chan = Channel<T>()
+suspend fun <T, R> CoroutineScope.fastest(vararg deferredArray: DeferredTransform<T, R>): R {
+    val chan = Channel<R>()
     val mutex = Mutex()
     deferredArray.forEach {
         launch(Dispatchers.IO) {
             try {
                 val result = it.deferred.await()
-                NetCancel.cancel(coroutineContext[CoroutineExceptionHandler])
                 mutex.withLock {
+                    NetCancel.cancel(coroutineContext[CoroutineExceptionHandler])
                     if (!chan.isClosedForSend) {
                         val transformResult = it.block(result)
                         chan.send(transformResult)
-                        chan.close()
                     }
                 }
             } catch (e: Exception) {
                 it.deferred.cancel()
                 val allFail = deferredArray.all { it.deferred.isCancelled }
-                if (allFail) throw e else e.printStackTrace()
-            } finally {
-                chan.close()
+                if (allFail) throw e else {
+                    if (e !is CancellationException) e.printStackTrace()
+                }
             }
         }
     }

+ 17 - 0
sample/src/main/java/com/drake/net/sample/ui/fragment/FastestFragment.kt

@@ -55,5 +55,22 @@ class FastestFragment : Fragment() {
         假设并发的接口返回的数据类型不同  或者 想要监听最快请求返回的结果回调请使用 [Deferred.transform] 函数
         具体请看文档 https://liangjingkanji.github.io/Net/fastest/
         */
+
+        // scopeNetLife {
+        //
+        //     // 同时发起四个网络请求
+        //     val deferred = Get<String>("api").transform {
+        //         23
+        //     } // 错误接口
+        //     val deferred1 = Get<String>("api1").transform {
+        //         50
+        //     } // 错误接口
+        //     val deferred2 = Post<String>("api").transform {
+        //         100
+        //     }
+        //
+        //     // 只返回最快的请求结果
+        //     tv_fragment.text = fastest(deferred, deferred1, deferred2).toString()
+        // }
     }
 }