Hi,
I get confusing warning in Android Studio about “blocking method call” in coroutine, and I’d like to understand how to avoid this.
I run “blocking method”, which compiler assumes by @Throws(IOException::class) annotation. If I remove the annotation, the warning goes away.
But OK, let’s assume that my doIO function is blocking by waiting for some I/O.
I run it from a coroutine that runs using a thread executor, so I know that it’s not running on main thread. Yet the IDE writes warning.
If I’d rewrite this as scope.launch(Dispatchers.IO){}, then warning goes away. If I rewrite it as scope.launch(Dispatchers.Default) {} (which also doesn’t run on main thread as I know), then warning is back.
So please someone experienced with this, can you explain how is it made that Dispatchers.IO is considered to be dispatcher for blocking calls, and other dispatchers including mine are not?
Thank you
private val executor = Executors.newSingleThreadExecutor()
val scope = CoroutineScope(SupervisorJob() + executor.asCoroutineDispatcher())
@Throws(IOException::class)
fun doIO(){
}
fun main(){
scope.launch {
doIO() // << warning here
}
}
Coroutines should never call blocking functions. The reason is simple, blocking functions block a thread and therefor stop any other coroutines to be executed on that thread. A better solution is to use suspending calls that just suspend the coroutine instead of blocking the thread (classic example is Thread.sleep vs delay).
But in reality there are a few functions that are blocking in nature, IO being one of the main examples. The way to solve this is by having a special dispatcher that can create as many threads as it needs. The problem with your scope executor is that it can at most use a single thread. So the first blocking call will block that thread, stopping all other coroutines as well because there is no thread to execute the coroutine.
The IO dispatcher on the other hand will just create an additional thread if all threads are used.
So the question now is “Why not use IO for everything?” Well, creating threads is expensive so you want to create as few as possible. If you were to create one thread for each coroutine you would tank your performance. The IO dispatcher is desinged specifically to handle blocking calls, while trying to minimize the performance overhead from creating additional threads, but also ensuring that you don’t run into deadlocks.
I don’t agree. Maybe send source from which you take this statement.
Can you imagine that by intention I use coroutines on single thread including blocking IO…? I’ve built video player (replacement of Android’s MediaPlayer) using coroutines run in single thread. I was able to replace bunch of callback-based functions by coroutines, assuring that only one thread does the work, no matter if it’s “blocking I/O” (function throwing IOException).
I would not limit use of coroutines to “intended behhavior” that called function should not block for some time, if that’s on purpose.
But there is other part of question - how compiler knows that Dispatchers.IO is different from Dispatchers.Default? If there was annotation to mark my dispatcher same way, and hide the warning, I’d do this. Maybe IDE has hard-coded check for Dispatchers.IO?
This may be question for Kotlin makers: how can I avoid the warning that I get?
It’s not the compiler, but IDEA inspection.
Jetbrains is trying to make clever “guess” - if your method throws IOException, it should dispached on IO thread pool.
How to avoid warning:
Remove @Throws, Kotlin don’t need it
Suppress warning in IDEA with annotation @Suppress("BlockingMethodInNonBlockingContext")
Tried, but not worked for me - create your own custom annotation for functions and add it to “non-blocking” list in inspection settings