I'm having trouble grasping something basic about ...
# coroutines
e
I'm having trouble grasping something basic about coroutines (even though I understand concurrency in other programming languages). Why is it necessary for responsiveness to have both
launch
(which presumably puts something on another thread) and
suspend
functions, which enable that thread to be used for another coroutine? I'm working in the context of Android, where it's vital that the main thread not get blocked. Why isn't launching a database access, for example, sufficient to guarantee main thread responsiveness? Is the issue that there are a small number of worker threads so no single database access should monopolize one?
c
It’s easiest to think of coroutines as putting “tasks” into a queue, and a Dispatcher grabs tasks from the queue to execute them. All the
launch { }
function does it put its block at the back of the queue, but by default it doesn’t change the dispatcher it’s running on. When you
launch { }
from the
lifecycleScope
or
viewModelScope
, you’re posting a task to the dispatcher of that scope, namely
Dispatchers.Main.immediate
, which is a dispatcher constrained to a single thread (the Main Thread in Android) That said, since needing to launch onto a different dispatcher is so common, there’s an overload available that accepts a
CoroutineContext
such as
<http://Dispatchers.IO|Dispatchers.IO>
, which will launch into that instead of the current dispatcher:
Copy code
viewModelScope.launch(<http://Dispatchers.IO|Dispatchers.IO>) { }
which is functionally equivalent to
Copy code
viewModelScope.launch {
    withContext(<http://Dispatchers.IO|Dispatchers.IO>) { }
}
e
Thank you so much, @Casey Brooks!
l
launch
does not mean thread switching, it just means launch something (without waiting for it), unlike a plain suspend function call. What is important is that blocking code is wrapped in the the right dispatcher (
<http://Dispatchers.IO|Dispatchers.IO>
for I/O like db, files… and
Dispatchers.Default
for allocation, other CPU using tasks…)
☝️ 1
✔️ 2
When I mean wrap, I mean like the following, because it actually works:
<http://Dispatchers.IO|Dispatchers.IO> { … }
It works the same with `withContext(Dispatchers.IO) { … }`FYI.