Hi. I have some questions about the coroutine scop...
# coroutines
k
Hi. I have some questions about the coroutine scope. What is the difference between the scope created with
coroutineScope()
and the scope created with
launch()
or
async()
? Both
coroutineScope()
and
launch()
create new instance of CoroutineScope (maybe AbstractCoroutine), the both do create new coroutine scope, right? If the coroutine throws an error, the parent coroutine will be canceled too. But if the coroutine inside of the scope created by
coroutineScope()
throws an error, the coroutine that called the
coroutineScope()
will not be canceled. Why? Is it that the coroutine created by
coroutineScope()
is not a child of the coroutine that did call
coroutineScope()
? Or there is something different between the two scopes? This very confuses me to understand what the coroutine scope is.
g
But if the coroutine inside of the scope created by
coroutineScope()
throws an error, the coroutine that called the
coroutineScope()
will not be canceled. Why?
Because this is use case of coroutineSccope This function created to run a few coroutines inside and do not let them leak in case of error and after successful invvocation return result. Also it suspends until all internal coroutines are finished
Is it that the coroutine created by
coroutineScope()
is not a child of the coroutine that did call
coroutineScope()
?
it chiled, why do you think so?
Or there is something different between the two scopes?
Just each coroutine builder has own semantics about error handling
did you read docs about coroutine scope and structured concurrency? https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/basics.md#structured-concurrency
If the coroutine throws an error, the parent coroutine will be canceled too.
Because coroutineScope is not a coroutine, this is suspend function, so this is use case of coroutineScope function
d
oh on that note, what makes up a coroutine?
g
Do you understand difference between coroutine and suspend function?
coroutine is object with state machine, which you create using launch/async or other coroutine builders
suspend function is what creates steps of this state machine, coroutines created and may run in parallel with other coroutines, but suspend function inside of coroutine is always sequential
so use case of
coroutineScope{}
(which is suspend function) is run some block, start a few coroutines inside, while those child coroutines are running coroutineScope is suspended, if one of them failed, coroutineScope throws exception, if all are finished it returns result. So it allows you to do some parallel work completely save and
coroutineScope{}
behaves exactly like any other sequential function, throws error or return succcessfully
d
that makes sense, cheers
g
But you cannot run a few
coroutineScope{}
in parallel (as any other suspend function), to do that you should start new coroutine using launch/async and to do this you need CoroutineScope instance, so you always has child/parent relations and it is StructuredConcrency approach that forces you to be explicit about lifecycle of any background job (any coroutine) But you can call
coroutineScope
from any suspend funcction, you don’t need other scope, because this function semantics is safe by definition (return success or throw, suspend during child coroutine invocation)
also, there is
supervisorScope
, which doesn’t throw automatically on child coroutine failure, so you can handle exception yourself https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/exception-handling.md#supervision
k
Thank you for your help!
did you read docs about coroutine scope and structured concurrency?
Yes, I’ve read that article.
In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using coroutineScope builder. It creates new coroutine scope and does not complete until all launched children complete.
This article says that
coroutineScope()
creates new coroutine scope, so I supposed
coroutineScope()
creates new scope but
launch()
and
async()
does not. But actually
launch()
and
async()
creates its new coroutine scope, is it correct udnerstanding? I was supposing this difference (
coroutineScope()
creates scope but
launch()
doesn’t) cause behavior difference (
coroutineScope()
doesn’t cancel its parent but
launch()
do) when child coroutine throws un error. My new understanding for the
coroutineScope()
function is: - The purpose of
coroutineScope()
is not just providing new CoroutineScope unlike as its name. - This is the suspending function which processes a set of processes including to launch coroutines, and it suspends until all its child coroutines finished. - The coroutines launched in its scope will be canceled when its child coroutines throw un error or the coroutine that did call
coroutineScope()
canceled. - But even if its child coroutines throw un error, the ScopeCoroutine (it is launched by
coroutineScope()
) will never cancel its parent job unlike other coroutines. There is any misunderstanding?
g
launch and async also create coroutine scopes
coroutineScope doesn't cancel parent scope because it doesn't know about parent scope, only about context and as any other suspend function doesn't try to cancel parent context Job, just throws an exception
k
Ok. I understood. Thank you so much.