android - Kotlin 协程启动{} vs 启动{ withContext{} }
问题描述
我的 Android 应用程序需要在后台(在服务内)进行一些文件读/写,首先我使用:
CoroutineScope(Dispatchers.IO).launch {
val fos = openFileOutput(fileName, MODE_PRIVATE)
val oos = ObjectOutputStream(fos)
oos.writeObject(myObj)
oos.close()
}
块内的每一行都有一个警告:“不适当的阻塞方法调用”
搜索问题后,我想我理解了 80%。所以基本上大多数协程只有 1 个线程,如果它被阻塞,那个协程将没有线程来做其他工作。为了解决这个问题,我们应该像这样把它包裹起来withContext
:
CoroutineScope(Dispatchers.IO).launch {
withContext(Dispatchers.IO) {
val fos = openFileOutput(fileName, MODE_PRIVATE)
val oos = ObjectOutputStream(fos)
oos.writeObject(myObj)
oos.close()
}
}
Android Studio 仍然显示警告。帖子说这只是Android Studio中的一个错误,这个解决方案很好。
我不明白的是,withContext
仍在运行Dispatchers.IO
。从launch
块来看,它可能看起来像是非阻塞的,但如果Dispatchers.IO
只有 1 个线程并且withContext
块在该线程上运行,那么该线程仍然被阻塞,不是吗?
我还了解到Dispatchers.IO
实际上有几乎无限的线程,它只是在需要时创建一个新线程。所以withContext
实际上不是阻塞,但如果这是真的,为什么我们需要withContext
阻塞?如果可以在需要时创建线程,那么第一个代码不会有任何问题Dispatchers.IO
,因此永远不会被阻塞,对吧?
解决方案
是的,这是一个带有警告的错误。Lint 无法检测到作用域正在使用什么 Dispatcher,我想他们只是假设您正在使用上下文使用的作用域 Dispatchers.Main
,因为这是最常见的。
您的 CoroutineScope (伪)构造函数具有带有 的上下文Dispatchers.IO
,因此launch
如果它不修改它,则继承该上下文,因此您启动的协程也使用Dispatchers.IO
. 所以,你的withContext
块是多余的。
解决方法是在启动时指定调度程序:
CoroutineScope(Job()).launch(Dispatchers.IO) {
val fos = openFileOutput(fileName, MODE_PRIVATE)
val oos = ObjectOutputStream(fos)
oos.writeObject(myObj)
oos.close()
}
另外,您的声明:
所以基本上大多数协程只有 1 个线程,如果它被阻塞,那个协程将没有线程来做其他工作。
具有误导性。协程没有线程,而 Dispatcher 有。有些调度程序有很多线程。
推荐阅读
- scala - 更新对象的 RDD
- xml - XSLT 条件比较不同元素之间的属性
- amazon-web-services - Azure DevOps 运行 Ansible Playbook
- sql - 如何在 SQL 中合并/合并/添加两个数组以形成一个新数组?
- python - 为什么我的瓶子服务器工作以命令 python 开始,而不是 python3?
- android - 从 xamarin Visual Studio 2019 上传发布版本时出错
- python - Python Requests 向任何 GET 或 POST 请求添加额外的标头
- excel - 将带有多个附件的电子邮件发送给多个收件人
- c# - 用户登录我的 Web 应用程序时如何获取用户的私有 IP 地址
- unity3d - Unity 中大型复杂网格的 LOD(使用 Blender)