Kotlin暂停功能是否在单独的线程上运行?

时间:2018-11-30 07:12:53

标签: kotlin coroutine kotlinx.coroutines

挂起功能在单独的线程上运行? 如果没有,那么性能收益是什么?

suspend fun requestToken():Token {..}  // takes 2 sec to complete
suspend fun createPost (token:Token){..} // takes 3 sec to complete

 suspend fun postItem() {
    val token = requestToken()
    val post =createPost(token)
    processPost(post)
  }

因此,当我们到达 processPost(post)时,如果未在单独的线程上运行suspend函数,则我们必须等待 requestToken() createPost(令牌)方法  完成(即2 + 3 = 5秒)。根据作者的说法,暂停是异步的,但是如果我们不产生任何新线程,那么我们如何实现异步行为呢?

3 个答案:

答案 0 :(得分:4)

  

暂停是异步的

ng-class="{active: $index == selected}" 与调用者同步执行。您实际上要说的是“无障碍”,这是一个完全不同的故事。

  

但是如果我们不产生任何新线程,那么我们如何实现异步行为?

您默认所有I / O必须在某个级别进行阻塞。错了非阻塞I / O的工作原理是将数据推送到发送缓冲区,并在接收缓冲区中有数据时接收通知。 suspend fun通过在将数据推送到发送缓冲区后挂起自身并安装回调程序(该回调程序将在接收缓冲区中的响应数据准备就绪时将其恢复)来挂起该机制。

答案 1 :(得分:1)

悬浮点只能在协程环境中使用,例如:

fun main() {
    delay(1000)
}

将不起作用,因为delay是一个暂停函数,编译器将不知道如何在没有协程的情况下处理该问题。当您拥有协程时,它可以使用一种称为调度程序的东西来控制线程所有权。挂起意味着该线程不再用于执行程序的那部分,而是执行其他操作或变为空闲状态。它的工作方式是,您可以同时运行多个协程,而不必每个线程都有一个线程,然后该线程可以执行每个协程的各个部分,直到一个挂起点。通常的想法是,您可以将挂起函数视为“生成器”,它们具有产生结果的阶段。

suspend fun hello() {
    println("Hello")
    delay(1000) // suspend here, let someone else use the thread while we wait
    println("World")
    delay(1000) // suspend again, we can still use the thread while waiting
    println("done")
}

每次被暂停时,它都会使用该线程来执行另一个函数,直到该函数暂停并且延迟到期为止,届时该函数将最终继续执行直到下一个暂停点或完全完成执行

这与阻塞代码不同,因为阻塞代码不会通过将线程置于 wait 状态而浪费线程,而是将其借用到另一个函数。这样一来,无需创建其他线程即可具有并发性,因为您仍然可以在没有真正的并行性的情况下使用多个函数,而使用并发执行部分函数。

协同程序并不一定能保护您免受阻塞,如果您呼叫Thread.sleep(1000),它仍然会成为阻塞呼叫。程序员有责任使用暂停等效项来阻塞函数,以最大限度地提高此概念的有效性。

有关更多详细信息,请阅读documentation,因为它非常详细且很有帮助。

答案 2 :(得分:-1)

可以显式声明线程池的背景单线程或多个后台线程,然后使用它,例如,通过将其作为参数传递,我们将此参数称为“调度程序”。真正有趣的是,它最初是从主线程启动的,然后自动切换到调度程序线程以在其上执行特定任务,并且虚拟机在此位置被挂起或中断,而主线程变得更凉爽的事情不受阻碍,并且可以在后台执行任务时执行其他操作。

任务完成后,虚拟机将立即返回到之前已被挂起或中断的位置,然后从该点恢复执行,但现在也从虚拟机的后台线程返回了结果。调度程序,下面是代码片段:

private val backgroundThread = ThreadPoolExecutor(1, 1, 15L, TimeUnit.SECONDS, LinkedBlockingQueue())

GlobalScope.launch(Dispatchers.Main, CoroutineStart.DEFAULT) {
    postItem(backgroundThread))
}

suspend fun CoroutineScope.postItem(scheduler: ThreadPoolExecutor): Boolean {
    val token = requestToken(scheduler)
    val post = createPost(token, scheduler)
    return processPost(post, scheduler)
}

private suspend fun CoroutineScope.requestToken(scheduler: ThreadPoolExecutor): String {
    val def: Deferred<String?> = async(scheduler.asCoroutineDispatcher(), CoroutineStart.DEFAULT) {
        val token = networkApi.requestToken()
    }

    return def.await() ?: ""
}

private suspend fun CoroutineScope.createPost(token: String, scheduler: ThreadPoolExecutor): String {
    val def: Deferred<String?> = async(scheduler.asCoroutineDispatcher(), CoroutineStart.DEFAULT) {
        val post = networkApi.createPost(token)
    }

    return def.await() ?: ""
}

private suspend fun CoroutineScope.processPost(post: String, scheduler: ThreadPoolExecutor): Boolean {
    val def: Deferred<Boolean?> = async(scheduler.asCoroutineDispatcher(), CoroutineStart.DEFAULT) {
        val result = networkApi.processPost(post)
    }

    return def.await() ?: false
}