首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Kotlin Coroutine发射{} vs启动{ withContext{}

Kotlin Coroutine发射{} vs启动{ withContext{}
EN

Stack Overflow用户
提问于 2021-01-29 13:16:31
回答 2查看 5.1K关注 0票数 7

我的Android应用程序需要在后台(在服务中)进行一些文件的读写,首先我使用:

代码语言:javascript
复制
CoroutineScope(Dispatchers.IO).launch {
    val fos = openFileOutput(fileName, MODE_PRIVATE)
    val oos = ObjectOutputStream(fos)
    oos.writeObject(myObj)
    oos.close()
}

块内的每一行都有一个警告:“不适当的阻塞方法调用”。

在搜索这个问题之后,我想我已经理解了其中的80%。因此,基本上大多数Coroutine只有一个线程,如果它被阻塞了,那么coroutine将没有线程来执行其他工作。要解决这个问题,我们应该将它封装在withContext中,如下所示:

代码语言:javascript
复制
CoroutineScope(Dispatchers.IO).launch {
    withContext(Dispatchers.IO) {
        val fos = openFileOutput(fileName, MODE_PRIVATE)
        val oos = ObjectOutputStream(fos)
        oos.writeObject(myObj)
        oos.close()
    }
}

Android仍然显示警告。The post说它只是Android中的一个bug,这个解决方案很好。

我不明白的是,withContext仍然运行在Dispatchers.IO上。从launch块来看,它看起来像是非阻塞的,但是如果Dispatchers.IO只有一个线程,而withContext块在该线程上运行,那么该线程仍然被阻塞,不是吗?

我还了解到Dispatchers.IO实际上有无限个线程,它只是在需要时创建一个新线程。所以withContext实际上并不是阻塞,但是如果这是真的,为什么我们需要withContext块呢?如果Dispatchers.IO可以在需要时创建线程,那么第一段代码就不会有任何问题,因此永远不会被阻塞,对吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-01-29 13:37:35

是的,这是一个带有警告的bug。Lint无法检测作用域使用的是什么,我想他们只是假设您使用的是上下文使用Dispatchers.Main的作用域,因为这是最常见的。

您的CoroutineScope (伪)构造函数具有与Dispatchers.IO的上下文,因此如果launch不修改上下文,则launch继承该上下文,因此启动的协同窗口也使用Dispatchers.IO。因此,您的withContext块是多余的。

解决方法是在启动时指定dispatcher:

代码语言:javascript
复制
CoroutineScope(Job()).launch(Dispatchers.IO) {
    val fos = openFileOutput(fileName, MODE_PRIVATE)
    val oos = ObjectOutputStream(fos)
    oos.writeObject(myObj)
    oos.close()
}

此外,你的发言:

因此,基本上大多数

只有一个线程,如果它被阻塞了,那么Coroutine将没有线程来执行其他工作。

有误导性。协同器没有线程,分配器有线程。有些调度员有很多线程。

票数 6
EN

Stack Overflow用户

发布于 2021-01-29 13:32:35

似乎在Android中确实有一个bug。以下代码没有为我显示警告:

代码语言:javascript
复制
CoroutineScope(Dispatchers.IO).launch(Dispatchers.IO) {
    val fos = context.openFileOutput("", Context.MODE_PRIVATE)
    val oos = ObjectOutputStream(fos)
    oos.writeObject(myObj)
    oos.close()
}

您还应该知道,在这段代码和您共享的两段代码之间,实际上没有行为上的区别。在这三种情况下,代码都将在IO线程上执行。

  • CoroutineScope(context)
  • launch(context)
  • withContext(context

所有这些方法都只是指定协同上下文。默认情况下,launch使用coroutine作用域上下文,但您可以像上面所做的那样或者通过使用withContext来更改它。

因此,基本上大多数

只有一个线程,如果它被阻塞了,那么Coroutine将没有线程来执行其他工作。

Dispatchers.IO实际上默认为64个线程。

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

https://stackoverflow.com/questions/65955201

复制
相关文章

相似问题

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