首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >协程是如何被挂起的?

协程是如何被挂起的?
EN

Stack Overflow用户
提问于 2021-11-06 19:54:47
回答 2查看 192关注 0票数 1

来自kotlin文档

代码语言:javascript
运行
复制
A coroutine is an instance of suspendable computation. 
It may suspend its execution in one thread and resume in another one.
代码语言:javascript
运行
复制
delay is a special suspending function. 
It suspends the coroutine for a specific time. 
Suspending a coroutine does not block the underlying thread, but allows other coroutines to run and use the underlying thread for their code.

当一个协程挂起时,正在运行的线程可以自由地执行其他协程。例如,当您使用delay()callSomeAPI()时,它们是异步完成的。

我来自javascript世界。像setTimeout()fetch()这样的函数是在javascript callstack外部和浏览器环境内部执行的。

但是在我们的kotlin例子中,到底是谁在执行这些方法呢?难道不应该有一个线程来管理这些东西吗?那么,我们是否要启动一个新线程来处理协程中的异步代码呢?

EN

回答 2

Stack Overflow用户

发布于 2021-11-06 20:07:50

这真的取决于暂停的原因是什么。例如,如果我们挂起等待某个IO,那么很可能下面的另一个线程被用来阻塞这个IO。一些IO是基于事件的,所以OS通知我们的应用程序协程可以恢复。但在许多情况下,我们暂停等待另一个协程,例如,我们等待它的完成,或者我们等待对Channel (可挂起队列)的读取/写入。然后,就不需要额外的线程了--其他协程恢复我们的协程。delay()是另一个例子。我不确定它是如何在内部工作的,它肯定取决于目标平台,但我不怀疑它会做忙碌等待;-)我猜操作系统提供了某种计时器事件。

所以再说一次:这要看情况。

票数 3
EN

Stack Overflow用户

发布于 2021-11-09 06:55:13

代码语言:javascript
运行
复制
import kotlinx.coroutines.*
import java.util.concurrent.Executors

suspend fun main(args: Array<String>) {
    coroutineScope {
        val start = System.currentTimeMillis()
        launch(Executors.newSingleThreadExecutor().asCoroutineDispatcher()) { // #1 
            launch {
                println("1 --> : " + (System.currentTimeMillis() - start))
                Thread.sleep(1000L)
                println("1 <--: " + (System.currentTimeMillis() - start))
            }

            launch { // #3
                println("2 --> : " + (System.currentTimeMillis() - start))
                delay(1000L)
                println("2 <--: " + (System.currentTimeMillis() - start))
            }
        }
    }

    coroutineScope {
        val start = System.currentTimeMillis()

        launch(Executors.newScheduledThreadPool(8).asCoroutineDispatcher()) { // #2
            launch {
                println("1` --> : " + (System.currentTimeMillis() - start))
                Thread.sleep(1000L)
                println("1` <--: " + (System.currentTimeMillis() - start))
            }

            launch { // #4
                println("2` --> : " + (System.currentTimeMillis() - start))
                delay(1000L)
                println("2` <--: " + (System.currentTimeMillis() - start))
            }
        }
    }
}

示例输出:

代码语言:javascript
运行
复制
1 --> : 56
1 <--: 1063
2 --> : 1063
2 <--: 2086
1` --> : 7
2` --> : 8
1` <--: 1012
2` <--: 1012

注意#1和#2行,在#1中,我们使用单线程执行器启动协程(类似于Dispatchers.Main),所以协程的后端是单线程,当我们调用阻塞函数Thread.sleep时,在#3中没有更改启动协程,所以在整个启动之后调用#3。

至于#2,同样的事情也会发生,但还有很多剩余的线程可以让#4启动

所以

,但是在我们的kotlin例子中,到底是谁在执行这些方法?难道不应该有一个线程来管理这些东西吗?那么,我们是否要启动一个新线程来处理协程中的异步代码呢?

不是线程,而是CoroutineContext、E.S.P. CoroutineIntercepter,它可以在CoroutineBuilder的参数(比如launch或其他)或父作用域中定义,

所有的东西都不是特定于os/平台的,而是由程序员控制的用户域调度器。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69867430

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档