I'm trying to understand coroutines and I have a q...
# coroutines
m
I'm trying to understand coroutines and I have a question: why does
c2
method hang here ?
d
Because the scope provided by
runBlocking
has a dispatcher that wraps a single threaded event loop
The
async
call is waiting on the
producer()
invocation to become available, which in turn is waiting on the thread to become available that is used by
async
m
@Dico ok, so what would be the simplest solution to fix it ?
runBlocking(newFixedThreadPoolContext(10, "a") { ... }
?
d
You could use any multithreaded dispatcher. runBlocking won't work with a dispatcher that isn't an event loop
m
@Dico could you give some example of a multihreaded, event-loop dispatcher ?
d
Um, I think it's internal api. Read the docs.
g
No, runBlocking has nothing with it. This code hangs because you start coroutine in async. Async never returns because waits all child coroutines work finish, but because producer’s channel is never closed it will never return, this is how parent/child relationships work with structured concurrency
If you really want to create global coroutine and manage lifecycle manually, do not do this
async { producer() }.await()
which starts new coroutine (async) and async itself creates another one and waits for child coroutine work result to avoid leaks. If you really need channels that can be consumed globally, just use GlobalScope:
Copy code
async { GlobalScope.producer() }.await()
d
Right, the task inside
produce
can't be started because it's been scheduled on this particular dispatcher with one thread. Thus,
async
needs to suspend first.
async
can only complete when
produce
started and invoked
close()
g
No, dispatcher is not involved
d
However, that has everything to do with
runBlocking
because this wouldn't block otherwise, on default dispatcher for example
g
problem with StructuredConcurrency
nono, see, no dispatching problems there
d
Can you explain once more?
g
even if you replace runBlocking with any other coroutine builder you will get the same
async { producer() }.await()
awiat() will never return
d
Well, why?
g
because
producer()
is a new coroutine that never finishes (because nobody consumes value from channel)
this is how coroutines scopes work
async {}
is scope
d
Ah, it needs to be consumed. That makes sense
g
so every child coroutine will be attached to this scope
and this producer coroutine is attached and async cannot return value before all child coroutines are finished, otherwise coroutine may leak
d
I get that, yeah, but i didn't know it isn't considered completed unless all values were consumed
g
produce is just a coroutine with channel and coroutine cannot finish until channel is open
d
What kind of channel is used by default? Rendezvous?
Because it does invoke
close()
on the channel
g
yes
this this is Rendezvous
d
Right, so
send
will suspend and thus
close()
is not reached unless the value is consumed
g
close()
is useless in general. because it will be closed when produce block return
d
Fair enough
g
yes, send suspend and coroutine is working forewer
d
If it were another kind of channel though it might work, right?
Like unlimited, conflated
g
I’m not sure that such pattern is good in general when you create some produce coroutine in some other not related coroutines, even if you fix it with GlobalScope there is a chance that nobody consume it and you will leak coroutine, if you have 1 it’s fine, what if create millions of them
d
I agree
g
depends on what you consider as “work”.
d
You mean it's good that
await()
waits on the channel to prevent you making ones unnecessarily
g
I don’t think that it will work in any case
because if send will not suspend, channel will be closed
d
I'm not able to test right now
g
You mean it’s good that
await()
waits on the channel to prevent you making ones unnecessarily
Yes, this is child/parent relationships that doesn’t allow to start async background task in nowhere. At least you should be explicit and use GlobalScope
Just concider
async { produce {} }
as
async { launch {} }
, so you don’t want to start launch coroutine and do not wait for result