Description
When one start to use Kotlin Coroutines it may sometime be tempting to use runBlocking
.
But in produciton it is generally a bad idea.
First of all it blocks a thread, which waste resources.
And it can also create a deadlock when called from a single-threaded context and one suspend until something is done that context. Here’s an example using JavaFx:
@FXML
fun handleAction() { // <-- Invoked by the JavaFx platform on the JavaFx platform thread
runBlocking { // <-- Blocks the JavaFx platform thread
// The following, schedule a job on the JavaFx platform thread and suspend until it has been executed.
// but since the thread is currently blocked it will never be executed, and thus create a deadlock freezing the UI.
withContext(Dispatchers.JavaFx) {
pritnln("hello from UI thread")
}
}
}
Snippet of non-compliant code
fun usage() {
runBlocking {
delay(1000)
}
}
Snippet of compliant code (fixing the above noncompliant code)
suspend fun usage() {
delay(1000)
}
or
fun usage() {
GlobalScope.launch { delay(1000) }
}
External references
The documentation of runBlocking itself states:
This function should not be used from coroutine. It is designed to bridge regular blocking code to libraries that are written in suspending style, to be used in main functions and in tests.
The kotlin team working on coroutines even wanted to make runBlocking
fail fast when invoked from some UI threads: Fail-fast when trying to do `runBlocking` from Android UI thread · Issue #227 · Kotlin/kotlinx.coroutines · GitHub.
Type : Bug
May slow down the application or worse: cause deadlocks.
I would personally set the default severity to “Critical”
Tags
performance, multi-threading, pitfall
Scope: Production
runBlocking
is legit and needed in tests.