我的Android应用程序需要在后台(在服务中)进行一些文件的读写,首先我使用:
CoroutineScope(Dispatchers.IO).launch {
val fos = openFileOutput(fileName, MODE_PRIVATE)
val oos = ObjectOutputStream(fos)
oos.writeObject(myObj)
oos.close()
}块内的每一行都有一个警告:“不适当的阻塞方法调用”。
在搜索这个问题之后,我想我已经理解了其中的80%。因此,基本上大多数Coroutine只有一个线程,如果它被阻塞了,那么coroutine将没有线程来执行其他工作。要解决这个问题,我们应该将它封装在withContext中,如下所示:
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可以在需要时创建线程,那么第一段代码就不会有任何问题,因此永远不会被阻塞,对吗?
发布于 2021-01-29 13:37:35
是的,这是一个带有警告的bug。Lint无法检测作用域使用的是什么,我想他们只是假设您使用的是上下文使用Dispatchers.Main的作用域,因为这是最常见的。
您的CoroutineScope (伪)构造函数具有与Dispatchers.IO的上下文,因此如果launch不修改上下文,则launch继承该上下文,因此启动的协同窗口也使用Dispatchers.IO。因此,您的withContext块是多余的。
解决方法是在启动时指定dispatcher:
CoroutineScope(Job()).launch(Dispatchers.IO) {
val fos = openFileOutput(fileName, MODE_PRIVATE)
val oos = ObjectOutputStream(fos)
oos.writeObject(myObj)
oos.close()
}此外,你的发言:
因此,基本上大多数
只有一个线程,如果它被阻塞了,那么Coroutine将没有线程来执行其他工作。
有误导性。协同器没有线程,分配器有线程。有些调度员有很多线程。
发布于 2021-01-29 13:32:35
似乎在Android中确实有一个bug。以下代码没有为我显示警告:
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个线程。
https://stackoverflow.com/questions/65955201
复制相似问题