is there any difference in terms of efficiency be...
# coroutines
t
is there any difference in terms of efficiency between doing this
urls.map {
GlobalScope.async { fetchLink(it) }
}.awaitAll().flatMap { it }
versus doing this?
urls.map {
GlobalScope.async { fetchLink(it) }
}.flatMap { it.await() }
o
assuming
urls
is a List, yes --
.awaitAll()
will build an extra list
as a point of coroutines, there's no difference, but I will say you shouldn't be using
GlobalScope
here most likely
t
huh? what should I be using instead?
i want to fetchLinks in parallel? @octylFractal
o
if you're already in a
suspend
context:
Copy code
coroutineScope {
  urls.map { async { fetchLink(it) }.flatMap { it.await() }
}
if you're not, replace
coroutineScope
with
runBlocking(Dispatchers.Default)
t
yes
urls
is a List
okay thanks. I am not in the suspend context. i dont understand why not use GlobalScope here?
o
doing it this way ensures that if one of the
async
calls fails, it will cancel all of the other
async
calls properly, and ensure that exceptions are propagated properly
t
interesting, is there a docs about this @octylFractal as I would love to read more? so basically i will use runblocking and the flatmap version is what your suggesting?
o
https://medium.com/@elizarov/the-reason-to-avoid-globalscope-835337445abc is probably one of the better articles about explicitly why not to use GlobalScope
a
awaitAll
will fail as soon as one of the
fetchLink
calls fails, as opposed to only as soon as the
fetchLink
calls before it in the list have completed/failed i.e. if the calls are taking a long time, it can make a difference to use
awaitAll
, as that would propagate a failure sooner (and cancel the siblings)
t
thanks @araqnid but thats that opposite of what @octylFractal said?
“*Octavia Togami*  [9:39 AM] doing it this way ensures that if one of the 
async
 calls fails, it will cancel all of the other 
async
 calls properly, and ensure that exceptions are propagated properly”
a
That will happen whether you call await() on each or awaitAll() on the list, and using a coroutineScope{} to isolate the cancellation to just these fetches is still advisable
o
hmm, yes, I was not aware that
awaitAll()
had differing behavior
g
If you use proper coroutineScope, or any other wrapping scope, there is no difference in behavior of await() and awaitAll(), because parent Job also will be cancelled on first fail As was said before, you shouldn't really use GlobalScope in such case
t
thanks all
l
@gildor You are right! I tested it out. But why is the official documentation saying the exact opposite? https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/await-all.html
g
I believe it's just a bit obsolete doc
Yes, awaitAll() is not exactly the same, it was important before introduction of structured concurrency
But after introduction of structured concurrency and when default Job cancellation startegy was changed (before it worked as SupervisorJob), it has the same behaviour
So now this doc should be changed and should say that it's not the same with SupervisorJob or without using parent scope
👍 2