The documentation for `<http://Dispatchers.IO|Disp...
# coroutines
s
The documentation for
<http://Dispatchers.IO|Dispatchers.IO>
says:
Copy code
This dispatcher shares threads with a [Default][Dispatchers.Default] dispatcher, so using
`withContext(<http://Dispatchers.IO|Dispatchers.IO>) { ... }` does not lead to an actual switching to another thread &mdash;
typically execution continues in the same thread.*
This behavior seems wrong to me. Isn’t the goal of
<http://Dispatchers.IO|Dispatchers.IO>
to keep
Dispatchers.Default
threads free. Sharing threads between the dispatchers seems counterintuitive to this goal.
m
Threads are expensive, particularly on constrained environments (e.g., Android devices). I imagine that part of the objective here was to minimize the number of threads that the built-in dispatchers would employ, since you can always use your own dispatcher (e.g,. built from a
ThreadPoolExecutor
in Kotlin/JVM) if you want. And I wouldn't say that
<http://Dispatchers.IO|Dispatchers.IO>
is to keep
Dispatchers.Default
threads free. It is to provide a separate dispatcher that is aware of long-running/low-CPU work.
Dispatchers.Main
explicitly has a separate thread from `Dispatchers.Default`+`Dispatchers.IO`, because we want
Default
and
IO
to keep
Main
free.
s
I agree that threads are relatively expensive, but they aren’t that expensive that doing this would be a priority. Also, there are other worlds besides mobile that this library is used in.
Default
is constrained by the number of CPU’s by default, meaning it can be meant for CPU intensive work, and
IO
by default has a max of 64 threads. By sharing threads between
IO
and
Default
, isn’t there a situation where I have 10 network requests running on the
IO
dispatcher, using a blocking java library, but I can’t perform any work on the main dispatcher because my network requests have settled into my
Default
threads and aren’t allowing them to be free? The natural inclination is for me to offload CPU intensive work to the
Default
dispatcher, and offload low-cpu blocking work to the
IO
dispatcher. This possible restriction would be terrible for a server environment, and forces me to either 1. Create a new dispatcher for blocking network requests / file accesses, or 2. Don’t use the
Default
dispatcher for cpu intensive work, or 3. both 1 and 2.
Also, I bought your book to teach myself programming / Android development in 2010 when I was in college, and even attended some office hours with you. It’s truly a pleasure to be having this discussion with you now.
❤️ 2
t
Blocking IO won't limit your Default count 🙂 New threads will be started to have the proper Default as needed.
1
s
@Tolriq So if there is a thread that’s shared between both dispatchers, and that thread gets used for a blocking IO operation, how wouldn’t it be used for the default count? Are the dispatchers that intelligent that they can borrow and share threads?
d
Yes
t
Yes 🙂
s
can anyone explain to me how it works?
t
(In theory, in practice there's still some issues preventing IO threads to be released on some circumstances and too much Default threads to be created) But those issues does not prevent it from working, just a little too much resources in some cases.
Read the code ?:)
s
lol direct me to where I’d be interested in please 😛
Also - this is a big picture idea that might not be super obvious in the nit of code
d
Just think of it as
Default
and
IO
dispatchers sharing a single thread pool.
t
For JVM at least
And as Mark said, you can (should) create your own dispatchers when needed, all default threads from coroutines have default priority and can easily impact the rest of the app, custom threadpool with lower priority can help.
d
If a coroutine needs to switch dispatchers, conceptually the coroutine will be moved off the running thread in
Default
, the thread will be returned to the shared pool, then
IO
will take a thread from the shared pool and run the coroutine on it. This can be optimised by just leaving the coroutine in the same thread, instead of "releasing" and "acquiring" the thread.
👍 1
I hope I somewhat make sense.
👍 1
1
u
It is about optimizing the cost of context switches. Like @Dominaezzz explained, if you switch from default to io dispatcher, the thread is basically relabeled to be an io thread. Thereby reducing the count of default-dispatcher threads allowing the pool to create another default-dispatcher thread of needed.
If later on, your coroutine is dispatched back from io to default, the thread can be relabeled as default thread. Making the whole roundtrip without context switching