当前位置: 首页 > 知识库问答 >
问题:

Kotlin coroutines-延迟,它是如何工作的?

闾丘英悟
2023-03-14

因此,我需要开始考虑关联,最好是利用我对并发工具的现有知识来加快进程

我试着为他们跟踪Google codelab,虽然它给了我一点理解,但它也提出了许多未回答的问题,所以我试图通过编写一些代码、调试和查看日志输出来弄脏我的手。

根据我的理解,一个coroutine由两个主要构件组成;挂起函数是您执行工作的地方,而coroutine上下文是您执行挂起函数的地方,这样您就可以对coroutine将在哪个调度程序上运行有一个句柄。

private const val TAG = "Coroutines"

class MainActivity : AppCompatActivity(), CoroutineScope {
    override val coroutineContext: CoroutineContext = Job() + Dispatchers.Main

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        log("onCreate", "launching coroutine")
        launch {
            val resource = getResource()
            log("onCreate", "resource fetched: $resource")
            findViewById<TextView>(R.id.textView).text = resource.toString()
        }
        log("onCreate", "coroutine launched")
    }

    private suspend fun getResource() : Int {
        log("getResource", "about to sleep for 5000ms")
        Thread.sleep(5000)
        log("getResource", "finished fetching resource")
        return 1
    }

    private fun log(methodName: String, toLog: String) {
        Log.d(TAG,"$methodName: $toLog: ${Thread.currentThread().name}")
    }
}
2020-05-28 11:42:44.364 9819-9819/? D/Coroutines: onCreate: launching coroutine: main
2020-05-28 11:42:44.376 9819-9819/? D/Coroutines: onCreate: coroutine launched: main
2020-05-28 11:42:44.469 9819-9819/? D/Coroutines: getResource: about to sleep for 5000ms: main
2020-05-28 11:42:49.471 9819-9819/com.example.coroutines D/Coroutines: getResource: finished fetching resource: main
2020-05-28 11:42:49.472 9819-9819/com.example.coroutines D/Coroutines: onCreate: resource fetched: 1: main

现在,如果我更新getresources函数以使用挂起乐趣delay(5000)而不是使用thread.sleep(5000),如下所示:

private suspend fun getResource() : Int {
    log("getResource", "about to sleep for 5000ms")
    delay(5000)
    log("getResource", "finished fetching resource")
    return 1
}

然后我最终看到的让我困惑。我理解delaythread.sleep不同,但是由于我是在由dispatchers.main支持的coroutine上下文中运行它,所以我希望看到与使用thread.sleep相同的结果。

相反,我看到的是,在发生5秒延迟时,UI线程没有被阻塞,日志看起来像:

2020-05-28 11:54:19.099 10038-10038/com.example.coroutines D/Coroutines: onCreate: launching coroutine: main
2020-05-28 11:54:19.111 10038-10038/com.example.coroutines D/Coroutines: onCreate: coroutine launched: main
2020-05-28 11:54:19.152 10038-10038/com.example.coroutines D/Coroutines: getResource: about to sleep for 5000ms: main
2020-05-28 11:54:24.167 10038-10038/com.example.coroutines D/Coroutines: getResource: finished fetching resource: main
2020-05-28 11:54:24.168 10038-10038/com.example.coroutines D/Coroutines: onCreate: resource fetched: 1: main

所以,我的问题是,在这种情况下,如何延迟而不阻塞UI线程(即使我的suspend函数中的日志仍然指示该函数在主线程上运行...)

共有1个答案

艾仲渊
2023-03-14

将挂起函数视为使用接受回调的函数的一种方式,但不需要将回调传递给它。相反,回调代码是挂起函数调用下的一切。

以下代码:

lifecycleScope.launch {
    myTextView.text = "Starting"
    delay(1000L)
    myTextView.text = "Processing"
    delay(2000L)
    myTextView.text = "Done"
}

有点像:

myTextView.text = "Starting"
handler.postDelayed(1000L) {
    myTextView.text = "Processing"
    handler.postDelayed(2000L) {
        myTextView.text = "Done"
    }
}
suspend fun myDelay(length: Long) {
    Thread.sleep(length)
}
suspend fun myDelay(length: Long) = withContext(Dispatchers.IO) {
    Thread.sleep(length)
}
 类似资料:
  • 我刚开始学习Go,我对Go博客中使用defer更改命名返回值的一个示例感到困惑--defer、Panic和recover。 我在下面的代码中进行了测试,在函数中,它返回1,因为它不是上面提到的“没有参数的返回语句”。 我的问题是,在第一个示例中,周围的函数c有一个命名的返回值i,但是函数使用,在第二个示例中,我们可以看到,无论是什么值,它都应该返回1。但是为什么在更改延迟函数后,函数返回的值,而不

  • 问题内容: 我正在尝试用Java做某事,而我需要一些东西在while循环中等待/延迟几秒钟。 我想构建一个步进音序器,并且对Java还是陌生的。有什么建议么? 问题答案: If you want to pause then use java.util.concurrent.TimeUnit: TimeUnit.SECONDS.sleep(1); TimeUnit.MINUTES.sleep(1);

  • 假设我们有一个名为托管在tomcat上的服务提供商应用程序,用户单击指向SP a的链接。SP a没有看到提供的令牌,因此它会将用户重定向到IdP进行身份验证(通过某种方式提供SAML Authn请求)。然后,IdP将用户重定向到提供凭据的某个公共登录页面,假设这些凭据正确,IdP将创建一个SAML响应,其中包含一个令牌和一些关于主题的断言,并将其发送回SP a。SP a看到了这一点,并允许用户访问

  • 为了减少内核或跨进程内存泄漏(Spectre攻击),Linux内核1将使用一个新选项编译,引入到,以便通过所谓的retpoline执行间接调用。 这似乎是一个新发明的术语,因为谷歌搜索只是最近才使用(通常都是在2018年)。 1但是,它不是Linux特有的--类似或相同的构造似乎被用作其他操作系统缓解策略的一部分。

  • 我们知道主存域很少:年轻的、终生的(旧的gen)和PermGen。 年轻领域分为伊甸园和幸存者(有两个)。 OldGen用于生存的对象。 MaxTenuringThreshold防止对象过早地被最终复制到OldGen空间。这很清楚,也很容易理解。 但是它是如何工作的呢?垃圾回收器如何处理这些在MaxTenuringThreshold之前仍然存在的对象,以何种方式?它们位于何处? 对象被复制回幸存者

  • 在我加入的新项目中,他们一直交替使用术语Hibernate和JPA。所以,我试图深入研究代码并试图理解整个事情是如何工作的(我是Spring、JPA和Hibernate世界的新手)。我将尝试将代码放在这里以更好地理解:1)有一个@Configuration类,其中有以下内容: 因此,在这个配置类中,我们返回一个EntityManagerFactory。 2) 然后是一个标记为@persistor的