https://kotlinlang.org logo
Title
u

ursus

02/02/2023, 6:48 PM
coroutineScope {
    launch { foo() }
    bar()
}
coroutineScope {
    launch { foo() }
    launch { bar() }
}
are these equivalent?
b

Big Chungus

02/02/2023, 6:49 PM
Yes in terms of execution order
j

jw

02/02/2023, 6:51 PM
You definitely can observe different execution orders between those
b

Big Chungus

02/02/2023, 6:52 PM
Really? On what scenarios?
j

jw

02/02/2023, 6:54 PM
well I think the only time you wouldn't see a difference is if you were in an Unconfined dispatcher
j

Jacob

02/02/2023, 6:55 PM
call it in runBlocking and you'll get different execution order
j

jw

02/02/2023, 6:55 PM
if your mental model of
launch
is "post this to a queue" then if you don't post
bar
but instead execute it synchronously after posting
foo
it will run first
u

ursus

02/02/2023, 6:57 PM
but if I don't care about the order of getting started, and I only care that
coroutineScope
will await them both, then it doesn't matter/first has less overhead?
b

Big Chungus

02/02/2023, 6:57 PM
Ah, gotcha. It's like js event loop shit all over again! Apologies for spreading misinformation!
k

kevin.cianfarini

02/02/2023, 6:58 PM
A coroutinescope will always wait for all of its children to finish before it can itself finish
j

Jacob

02/02/2023, 6:58 PM
if the first line in`bar()` was
yield()
then they might appear to be in the same order
e

ephemient

02/02/2023, 6:58 PM
after
launch { foo() }
, it is not specified how much of
foo
has run before the next statement in the caller
j

jw

02/02/2023, 6:59 PM
that still depends on scheduling and dispatcher support of
yield
, but yes they might be the same sometimes
really you can't saying anything without knowing the dispatcher in use (with respect to order)
e

ephemient

02/02/2023, 7:00 PM
with
launch(start = CoroutineStart.UNDISPATCHED) { foo() }
you can say that up to the first suspension point in
foo()
has executed, I believe
and with
launch(start = CoroutineStart.LAZY) { foo() }
you should be able to say that none of it has executed
but otherwise… unspecified
u

ursus

02/02/2023, 7:01 PM
so given
io
dispatcher, then what is more idiomatic, if you only care that they're executed in parallel a nd coroutineScope awaits both of them
j

jw

02/02/2023, 7:01 PM
sure, but now you're changing the code. if the caller is using the Unconfined dispatcher
foo
will always run before
bar
j

Jacob

02/02/2023, 7:03 PM
I don't think one is more idiomatic than the other
e

ephemient

02/02/2023, 7:03 PM
I'd write whichever is clearer for the purpose
u

ursus

02/02/2023, 7:07 PM
well that's my question, what does look more clearer 😄 basically I want to sync two apis at once
coroutineScope {
	launch { syncInvoices() }
	launch { syncMessages() }
}
probably the dual launch makes it more apparent that they're both going in parallel?
c

Casey Brooks

02/02/2023, 7:08 PM
If the main thing you’re trying to express is 2 jobs running in parallel, I would make sure that’s explicit in the code. So yes, like the snippet above, I’d use 2
launch
blocks
e

ephemient

02/02/2023, 7:08 PM
if both launches are equally "async", then yes I'd write them both as
launch
u

ursus

02/02/2023, 7:10 PM
thanks!
and technically this
coroutineScope {
	launch { syncInvoices() }
	syncMessages()
}
says "syncMessages after enqueueing syncInvoices coroutine" ?
e

ephemient

02/02/2023, 7:18 PM
that's one way to look at it
g

gildor

02/03/2023, 6:05 AM
It is, but if one has to add one more "sync", they may be confused how to do this. So 2 launch blocks are easier to read and shows intent better