-
-
Notifications
You must be signed in to change notification settings - Fork 679
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix runBlocking in coroutines #4340
Fix runBlocking in coroutines #4340
Conversation
…s always called from a coroutine.
…ys called from a coroutine.
…unction is always called from a coroutine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @bbrockbernd
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍 |
Forgive me for asking what could be an obvious question, but can you link to an example or more specific documentation about this? I understand avoiding the use of |
Definitely! The documentation states that blocking a coroutine "potentially leads to thread starvation issues". (last sentence of https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html). Some intuition of why this can be dangerous: https://betterprogramming.pub/how-i-fell-in-kotlins-runblocking-deadlock-trap-and-how-you-can-avoid-it-db9e7c4909f1. In the end of the day, you want to avoid calling runBlocking from coroutines as much as possible. For instance, the android/app/src/main/java/io/homeassistant/companion/android/settings/language/LanguagesManager.kt Lines 41 to 42 in 177a040
However this function is called from SettingsPresenterImpl.putString(key: String, value: String?) from within a coroutine launched on the Main dispatcher. And thus blocking the UI thread.android/app/src/main/java/io/homeassistant/companion/android/settings/SettingsPresenterImpl.kt Lines 101 to 105 in 177a040
Since this is the only call site for saveLang we can easily turn this function into a suspend function and get rid of the runBlocking builder.
Now in the case of |
Thanks for the specific example and explanation, that makes it easier to follow :) These changes look good to me. There are also other places where |
No problem! As a matter of fact we are developing a tool that should be able to detect these runBlockings and are currently testing it on open source projects! It found actually one more occurence: io.homeassistant.companion.android.common.data.servers.ServerManagerImpl.removeServer However, I did not see a quick solution to solve this one.. The longer the callstack between runBlockings gets the trickier. |
Yes that one will be tricky so let's not touch it for now and do this PR first. |
Summary
I found a few occasions where the runBlocking coroutine builder is called from within other coroutines. This can affect performance since it blocks the thread that is shared among coroutines, and can in some cases lead to the infamous nested runBlocking deadlock. Often an easy fix is to turn the containing function into a suspend function.
Let me know if I missed something!
Cheers
Screenshots
Link to pull request in Documentation repository
Any other notes