【问题标题】:Coroutine suspend function and blocking calls协程挂起函数和阻塞调用
【发布时间】:2020-06-27 18:35:14
【问题描述】:

以下是我的用例。 我有一个函数fun requestFocus,这个函数又调用函数fun configure,它依赖于来自系统的回调,因此这个函数 configure 使用计数为 1 的 coundownlatch 并等待直到它在回调时重置为零已收到。 为此,我标记了 requestFocus 暂停并使用 Dispatchers.IO 来完成所有操作。 现在有多个 requestFocus 调用者用于前函数 fun acceptaccept 函数做了很多事情,所有事情都发生在同一个线程上。 accept 函数也可以从主线程或意图服务中调用。我的问题是因为函数配置被阻塞我不想阻塞主线程。 目前accept函数是这样的

fun accept() {
    //do something
    requestFocus()
    // do something
}

我不确定如何从 accept 调用 requestFocus 并让 requestFocus 执行后发生的所有操作以相同的方式发生。我目前在接受功能中所做的如下

fun accept() {
    //do something
    runBlocking{
    requestFocus()
    // do something
}

但这会产生问题,因为主线程被阻塞。任何建议我可以尝试什么?我查看了全球范围和主要范围的文档。

【问题讨论】:

  • 除非在单元测试中,否则不要使用runBlocking。否则它完全违背了协程的目的。使用lifecycleScope.launch 启动协程。这有点像将 Runnable 发布到主线程,但 lambda 中的代码可以挂起并因此调用 suspend 函数。所以如果accept()代表一个完整的逻辑流,就用fun accept() = lifecycleScope.launch { /*...*/ }

标签: android kotlin coroutine kotlin-coroutines


【解决方案1】:

您正在寻找withContext 块。 withContext 的行为类似于 runBlocking,但它暂停线程而不是阻塞它。

suspend fun accept() {
    //do something on calling thread
    withContext(Dispatchers.IO){ // Changes to Dispatchers.IO and suspends the calling thread
        requestFocus() // Calls requestFocus() on Dispatchers.IO
        // do something on Dispatchers.IO
    }
    // Resumes calling thread
}

您需要从协程范围或从另一个挂起函数调用accept。或者你可以用launch创建一个协程来启动一个协程:

fun accept() = launch(Dispatchers.Main) { // Starts a coroutine on the main thread
    //do something on main thread
    withContext(Dispatchers.IO){ // Changes to Dispatchers.IO and suspends the main thread
        requestFocus() // Calls requestFocus() on Dispatchers.IO
        // do something on Dispatchers.IO
    }
    // Resumes main thread
}

【讨论】:

  • 感谢您的帮助。这让我更清楚了一些事情。但是,正如我所说,可以从主线程和后台线程调用接受。那么是否有可能在线程接受被调用时启动(内部接受)?就像您的第二个解决方案一样,它将始终是主线程。所以只是好奇它是否可能在协程中
  • 这是可能的,但如果你想要类似顺序的执行,那么使用launch 将不起作用。当您使用launch 创建协程时,您正在创建一个子进程,并且创建该协程的线程不会被挂起,因此它将继续执行,因此accept 可能会在您在其中创建的协程完成之前完成。我的第二个解决方案创建一个协程并开始在主线程上运行,但如果您删除 Dispatchers.Main,它将创建一个协程并开始在您调用的任何线程上运行 accept
  • 谢谢。还有一件事,就像我说的那样,我正在使用 coundownlatch 并在 requestFocus 调用的 configure 方法中等待。我想知道它作为倒计时的好方法是否会保留线程并阻止它。 kotlin-coroutine 中有没有更好的选择。例如,我知道协程有延迟而不是 thread.sleep 与协程一起工作,倒计时用例是否有类似的东西?
  • 您可以使用协程复制 Countdownlatch 行为。例如,创建一个像 val job = launch(start = CoroutineStart.LAZY) {...} 这样的惰性协程,并在需要时以 job.start() 启动它。要验证协程是否正在运行,您可以这样做 if(job.isActive) {...} 并使用 job.join() 等待协程完成。
猜你喜欢
  • 2021-11-03
  • 2021-01-26
  • 2020-07-19
  • 1970-01-01
  • 1970-01-01
  • 2021-09-29
  • 1970-01-01
  • 2021-06-05
相关资源
最近更新 更多