简体   繁体   English

Kotlin 协程启动{} vs 启动{ withContext{} }

[英]Kotlin Coroutine launch{} vs launch{ withContext{} }

My Android app need to do some file read/write in background (inside a Service), first I use:我的 Android 应用程序需要在后台(在服务内)进行一些文件读/写,首先我使用:

CoroutineScope(Dispatchers.IO).launch {
    val fos = openFileOutput(fileName, MODE_PRIVATE)
    val oos = ObjectOutputStream(fos)
    oos.writeObject(myObj)
    oos.close()
}

Every single line inside the block has a warning: "Inappropriate blocking method call"块内的每一行都有一个警告:“不适当的阻塞方法调用”

After search the problem, I think I understand 80% of it.搜索问题后,我认为我理解了 80%。 So basically most Coroutine only has 1 thread, if it is blocked, that coroutine will have no thread to do other job.所以基本上大多数协程只有1个线程,如果它被阻塞,协程将没有线程来做其他工作。 To fix this, we should wrap it inside withContext like this:要解决这个问题,我们应该像这样将它包装在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 still shows the warning. Android Studio 仍然显示警告。 The post say it is just a bug in Android Studio, and this solution is fine. 帖子说这只是 Android Studio 中的一个错误,这个解决方案很好。

What I don't understand is, withContext is still run on Dispatchers.IO .我不明白的是, withContext仍在Dispatchers.IO上运行。 From the launch block, it may seem like non-blocking, but if Dispatchers.IO only has 1 thread and the withContext block is run on that thread, then that thread is still blocked isn't it?launch块来看,它可能看起来像非阻塞,但如果Dispatchers.IO只有 1 个线程并且withContext块在该线程上运行,那么该线程仍然被阻塞,不是吗?

I also learned Dispatchers.IO actually has virtually infinite threads, it just create a new one when needed.我还了解到Dispatchers.IO实际上有无限线程,它只是在需要时创建一个新线程。 So the withContext actually is not blocking, but if this is true, why do we need the withContext block?所以withContext实际上并没有阻塞,但如果这是真的,为什么我们需要withContext块? The first code won't have any problem if Dispatchers.IO can create thread when needed thus will never be blocked, right?如果Dispatchers.IO可以在需要时创建线程从而永远不会被阻塞,那么第一个代码不会有任何问题,对吧?

Yes, this is a bug with the warning.是的,这是一个带有警告的错误。 Lint can't detect what Dispatcher the scope is using, and I suppose they just assume that you're using a scope whose context uses Dispatchers.Main , since that is the most common. Lint 无法检测到 scope 使用的是什么 Dispatcher,我想他们只是假设您使用的是 scope,其上下文使用Dispatchers.Main ,因为这是最常见的。

Your CoroutineScope (pseudo-)constructor has a context with Dispatchers.IO , so launch inherits that context if it doesn't modify it, so your launched coroutine also uses Dispatchers.IO .您的 CoroutineScope(伪)构造函数具有Dispatchers.IO的上下文,因此如果不修改它, launch会继承该上下文,因此您启动的协程也使用Dispatchers.IO So, your withContext block is redundant.所以,你的withContext块是多余的。

Workaround would be to specify the dispatcher when launching:解决方法是在启动时指定调度程序:

CoroutineScope(Job()).launch(Dispatchers.IO) {
    val fos = openFileOutput(fileName, MODE_PRIVATE)
    val oos = ObjectOutputStream(fos)
    oos.writeObject(myObj)
    oos.close()
}

Also, your statement:另外,你的声明:

So basically most Coroutine only has 1 thread, if it is blocked, that coroutine will have no thread to do other job.所以基本上大多数协程只有1个线程,如果它被阻塞,协程将没有线程来做其他工作。

is misleading.具有误导性。 A coroutine doesn't have threads, a Dispatcher does.协程没有线程,而 Dispatcher 有。 And some Dispatchers have many threads.并且有些 Dispatcher 有很多线程。

It seems there's indeed a bug in Android Studio.似乎 Android Studio 中确实存在错误。 The following code shows no warnings for me:以下代码对我没有显示任何警告:

CoroutineScope(Dispatchers.IO).launch(Dispatchers.IO) {
    val fos = context.openFileOutput("", Context.MODE_PRIVATE)
    val oos = ObjectOutputStream(fos)
    oos.writeObject(myObj)
    oos.close()
}

You should also know that between this code and the two you shared, there's is virtually no difference in behavior.您还应该知道,这段代码与您共享的两段代码在行为上几乎没有区别。 In all three cases the code will be executed on the IO thread.在这三种情况下,代码都将在 IO 线程上执行。

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

All these methods just specify the coroutine context.所有这些方法都只是指定协程上下文。 By default launch uses the coroutine scope context, but you can change that either as I did above or by using withContext .默认情况下, launch使用协程 scope 上下文,但您可以像我上面所做的那样或使用withContext来更改它。

So basically most Coroutine only has 1 thread, if it is blocked, that coroutine will have no thread to do other job.所以基本上大多数协程只有1个线程,如果它被阻塞,协程将没有线程来做其他工作。

Dispatchers.IO actually defaults to 64 threads. Dispatchers.IO实际上默认为 64 个线程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 LifecycleScope.launch 与 onViewCreated 内的协程 - lifecycleScope.launch vs coroutine inside onViewCreated 使用 withContext 方法在 kotlin 协程中尝试捕获 - try-catch in kotlin coroutine with withContext method withContext 协程不工作。 在 Android 中使用 Kotlin - The withContext coroutine is not working. Using Kotlin in Android Android kotlin 处理程序和协程启动(IO)组合不起作用 - Android kotlin handler and coroutine launch(IO) combination not working Kotlin 的启动是在主线程还是后台线程中启动协程? - Does Kotlin's launch start a coroutine in the main or a background thread? 在 CoroutineScope.launch 之后的 withContext - CoroutineScope.launch 会阻塞吗? - withContext after a CoroutineScope.launch - will CoroutineScope.launch block? 无法启动协程生成器 - cant launch coroutine builder 使用 GlobalScope.launch 和 CoroutineScope().launch 启动协程有区别吗? - Is there a difference between using GlobalScope.launch and CoroutineScope().launch to launch a coroutine? Kotlin启动协程跳过了代码行,其中Google Volley从服务器检索信息 - Kotlin launch coroutine skips code line where Google Volley retrieves information from a server 协程 scope 内部 withcontext 并且仅 withContext 使用 - coroutine scope inside withcontext and only withContext usage
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM