Hi! I saw around a bunch of example where suspendi...
# coroutines
a
Hi! I saw around a bunch of example where suspending function gets defined with coroutineScope like in
Copy code
suspend fun myFun() = coroutineScope {}
I wonder, given that a suspending function must be called within a scope, what’s the point of creating a new scope like in there?
o
it creates a "child" scope, so that all work started by that function must complete before that function returns (unless you explicitly use another scope)
a
gotcha, so that means that if I have those 2 snippets
Copy code
suspend fun myFun() = coroutineScope {
    launch { timeExpensiveFun() }
}
and
Copy code
suspend fun myFun() =
    launch { timeExpensiveFun() }
the second function will return while launch will still be in progress, while in the first case myFun will wait for launch to be completed. Is that right? If this is the case would it be right to say that in my code I can use coroutineScope {} when I need to bridge sync and async world instead of runBlocking{} ?
o
the second one won't work in current coroutine land
a
how come?
o
launch
is defined as an extension of
CoroutineScope
, i.e.
fun CoroutineScope.launch
your second example has no
CoroutineScope
(at least in the example) and therefore will result in a compile error (the first one has it implicitly as
this
from
coroutineScope {}
)
a
sorry you’re right, I meant something like
Copy code
suspend fun myFun() =
    scope.launch { timeExpensiveFun() }
o
on the original question: the first one will wait you cannot use
coroutineScope
to bridge sync and async as it itself is
suspend
, but
runBlocking
already provides you with a
CoroutineScope
inside it just like
coroutineScope
yes, in that case the second example would not wait (and does not even need to be
suspend
) this is discouraged unless you really mean to do it though, structured concurrency is preferred when possible
a
got it, yeah sorry I’m still in trouble trying to understand when to use suspend 🙂
o
generally, use it when you need it 🙂 the compiler will tell you if you do
to be specific about the rule, it is needed to make a call to any
suspend
functions
👍 1
a
so just to make an example, say you have a class when you want to call different apis (and don’t mind about the results). Would you do something like this:
Copy code
fun callAllGuys() {
  private val scope = CoroutineScope(Executors.newFixedThreadPool(2).asCoroutineDispatcher())
  for (website in websites) {
      scope.launch(callWebsiteLambda())
  }
}
or do you think that’s wrong and there is a better example with structured concurrency?
z
You would probably define the scope as a class property instead, so that you can cancel the scope when the class is disposed/cancelled/shutdown whenever your architecture is done with it. And don't create a new thread pool, one of the advantages of using coroutines is that you get a high level of concurrency without allocating more threads. So something like this:
Copy code
class YourApiWrapper {
  private val scope = CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO>)

  fun callAllApis() {
    for (website in websites) {
      scope.launch { … }
    }
  }

  fun shutdown () {
    scope.cancel()
  }
}
👍 3