53

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

例如)

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

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

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

如果我想以 sum 方法返回总计,我该怎么做?

像,

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

    return total
}
4

6 回答 6

57

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

fun sum(): Int = runBlocking {
    funA().await() + funB().await()
}

请参阅协程指南中的桥接阻塞和非阻塞世界,以及组合挂起函数了解如何在协程sum 内部使用。

于 2017-11-01T14:35:06.357 回答
11

回答这个问题可能为时已晚,但希望有人会发现它很有用。下面的代码片段计算 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
                }
            }
        }
    }
}
于 2018-10-26T12:47:10.463 回答
9

添加另一种实现方式。

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
}
于 2018-11-23T15:13:30.740 回答
8

我编辑你的工作,我将 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()}")
}

希望它会有所帮助

于 2019-08-23T16:43:40.813 回答
6

这是另一种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()
}

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

CoroutineScope(Dispatchers.IO).launch {
    measureTimeMillis {
        Log.d("TAG", "sum=${sum().await()}")
    }.also {
        Log.d("TAG", "Completed in $it ms")
    }
}
于 2020-12-10T07:21:39.437 回答
1

这是我的做法,在尝试从我的 Room 数据库中删除电话号码时返回一个布尔值。您可以使用相同的模式来完成您想要完成的任务。在我的视图模型中:

private var parentJob = Job()
private val coroutineContext: CoroutineContext get() = parentJob + Dispatchers.Main
private val scope = CoroutineScope(coroutineContext)

suspend fun removePhoneNumber(emailSets: EmailSets, personDetails: PersonDetails) : Boolean  {
    var successReturn = false
    scope.async(Dispatchers.IO) {
        val success = async {removePhoneNumbersAsync(emailSets,personDetails)}
        successReturn = success.await()

    }
    return successReturn
}

fun removePhoneNumbersAsync(emailSets: EmailSets, personDetails : PersonDetails):Boolean {
    var success = false
    try {
        val emailAddressContact = EmailAddressContact(emailSets.databaseId, personDetails.id, personDetails.active)
        repository.deleteEmailAddressContact(emailAddressContact)
        val contact = Contact(personDetails.id, personDetails.personName, personDetails.personPhoneNumber, 0)  
        repository.deleteContact(contact)
        success = true
    } catch (exception: Exception) {
        Timber.e(exception)
    }
    return success
}

在我的活动中:

runBlocking {
    if (v.tag != null) {
            val personDetails = v.tag as PersonDetails
            val success  = viewModel.removePhoneNumber(emailSets,personDetails)
            if (success) {
                val parentView = v.parent as View
                (parentView as? TableRow)?.visibility = View.GONE
                val parentViewTable = parentView.parent as ViewGroup
                (parentViewTable as? TableLayout)
                parentViewTable.removeView(parentView)
            }
     }

}
于 2019-07-15T10:43:53.250 回答