Kotlin Coroutines具有回归价值

Exp*_* be 11 kotlin kotlinx.coroutines

我想创建一个具有返回值的协程方法.

例如)

fun funA() = async(CommonPool) {
    return 1
}

fun funB() = async(CommonPool) {
    return 2
}

fun sum() {
    launch {
        val total = funA().await() + funB().await()
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我想要求总和方法,我该怎么办?

喜欢,

fun sum(): Int {
    launch {
        val total = funA().await() + funB().await()
    }   

    return total
}
Run Code Online (Sandbox Code Playgroud)

Ale*_*nov 17

要准确地返回Int,你需要离开协程世界,这runBlocking就是:

fun sum(): Int = runBlocking {
    funA().await() + funB().await()
}
Run Code Online (Sandbox Code Playgroud)

请参阅协同指南中的桥接阻塞和非阻塞世界,以及如果要协同程序使用,请编写暂停函数以了解如何执行此操作.sum

  • 有没有一种方法可以在不阻塞主线程的情况下做到这一点? (3认同)
  • @Angelina 1.这将阻止调用此函数的线程,该线程可能是也可能不是主线程。2.做到这一点而又不阻塞调用线程的唯一方法是使“ suspend”变得有趣。有关更多信息,请参见第二个链接。 (2认同)

Men*_*ena 14

如果我正确理解你的问题,你想创建一个函数 ex。"doWork()"它确实可以在协程上运行,并直接简洁地返回该工作的结果,从而能够更新您的 UI 而不会冻结它。

因此,基于上述:

首先,我完全避免使用runBlocking,因为它最终会阻塞 UI 线程或主线程,直到 'doWork()' 在您指定的任何其他线程上完成其工作。

我发现实现您的目标的最合适的解决方案是使用 Koltin Flow,因为如果您将来愿意,您可以稍后发布进度。

就是这样:

fun doWork(): Flow<Int> =
        flow {
            //do long work 
           val sum:Int = doCalculations()
           emit(sum)
        }.flowOn(Dispatchers.Default)
Run Code Online (Sandbox Code Playgroud)

默认情况下,流程将在协程上运行。

在你看来,你调用这个函数:

launch(Dispatchers.Main){
    doWork().single{
    val my result=it
    //Update your UI
    }
}
Run Code Online (Sandbox Code Playgroud)

另一个更简单的解决方案:

将 doWork() 设为挂起函数

   suspend fun doWork(): Int =
          withContext(Dispatchers.Default){
                //do long work 
               val sum:Int = doCalculations()  
               return@withContext sum
}
Run Code Online (Sandbox Code Playgroud)

在你看来,你调用这个函数:

launch(Dispatchers.Main){
    val my result=doWork()
    //Update your UI
    }
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*lin 8

回答这个问题可能为时已晚,但希望有人会发现它有用。下面的代码片段计算 3 个值 A + B + C 的总和。每个值在其自己的后台线程中并行计算,然后所有中间结果合并为一个最终结果并返回到主线程以将其显示在屏幕上。

所以计算最终值需要 5 秒(不是 10 秒 = 2 + 3 + 5),结果显然是 6 并且它是非阻塞的,主线程可以在 sum() 执行未完成时处理其他事件。

suspend fun sum(scheduler: ThreadPoolExecutor): Int = coroutineScope {

    withContext(scheduler.asCoroutineDispatcher()) {
        val a = async { funA() }
        val b = async { funB() }
        val c = async { funC() }

        a.await() + b.await() + c.await()
    }
}

fun funA(): Int {
    Thread.sleep(2000L)
    return 1
}

fun funB(): Int {
    Thread.sleep(3000L)
    return 2
}

fun funC(): Int {
    Thread.sleep(5000L)
    return 3
}

class MainActivity : AppCompatActivity(), View.OnClickListener {
    private val tripletsPool = ThreadPoolExecutor(3, 3, 5L, TimeUnit.SECONDS, LinkedBlockingQueue())

   ...

    override fun onClick(view: View?) {
        if (view == null) {
            return
        }

        when (view.id) {
            R.id.calculate -> {
                GlobalScope.launch(Dispatchers.Main, CoroutineStart.DEFAULT) {
                    progressBar.visibility = View.VISIBLE
                    result.setText("${sum(tripletsPool)}")
                    progressBar.visibility = View.GONE
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Sah*_*bra 8

添加另一种实现方式。

fun sum(): Int {
    var sum: Int = 0
    runBlocking {
        val jobA = async { funA() }
        val jobB = async { funB() }
        runBlocking{
           sum = jobA.await() + jobB.await()
        }
    }
    return sum
}

suspend fun funA(): Int {
    return 1
}

suspend fun funB(): Int {
    return 2
}
Run Code Online (Sandbox Code Playgroud)

  • 你能解释一下为什么有两个 runBlocking 块吗? (3认同)

小智 7

我编辑了您的工作,将 funA 和 funB 更改为挂起函数,并为 sum 运算符创建了一个函数,并调用了 main 函数,示例如下:

suspend fun funA(): Int{
    return 1
}

suspend fun funB(): Int {
    return 2
}
fun sum() = runBlocking{
    val resultSum = async { funA.await() + funB.await() }
    return resultSum
}

fun main() = runBlocking{
    val result = async { sum() }
    println("Your result: ${result.await()}")
}
Run Code Online (Sandbox Code Playgroud)

希望它会有所帮助


Joo*_*soo 5

这里的另一种方式来运行funA(),并funB()没有使用并行runBlocking

fun funA() = CoroutineScope(Dispatchers.IO).async {
    delay(3000)
    return@async 1
}

fun funB() = CoroutineScope(Dispatchers.IO).async {
    delay(3000)
    return@async 2
}

fun sum() = CoroutineScope(Dispatchers.IO).async {
    val a = funA()
    val b = funB()
    return@async a.await() + b.await()
}
Run Code Online (Sandbox Code Playgroud)

如果你想在sum()不阻塞主线程的情况下运行,

CoroutineScope(Dispatchers.IO).launch {
    measureTimeMillis {
        Log.d("TAG", "sum=${sum().await()}")
    }.also {
        Log.d("TAG", "Completed in $it ms")
    }
}
Run Code Online (Sandbox Code Playgroud)