withContext suspend fun <T> withContext( context: CoroutineContext, block: suspend CoroutineScope.() -> T ): T (source) Calls the specified suspending block with a given coroutine context, suspends until it completes, and returns the result.
suspend fun <R> coroutineScope( block: suspend CoroutineScope.() -> R ): R (source) Creates a CoroutineScope and calls the specified suspend block with this scope. The provided scope inherits its coroutineContext from the outer scope, but overrides the context’s Job.
the withContext takes CoroutineContext, and both seems to be complete
after all its children are complete.
In what case the withContext
or the coroutineScope
should be preferred than the other?
for example:
suspend fun processAllPages() = withContext(Dispatchers.IO) { // withContext waits for all children coroutines launch { processPages(urls, collection) } launch { processPages(urls, collection2) } launch { processPages(urls, collection3) } }
could also be
suspend fun processAllPages() = coroutineScope { // coroutineScope waits for all children coroutines launch { processPages(urls, collection) } launch { processPages(urls, collection2) } launch { processPages(urls, collection3) } }
are the both processAllPages()
doing the same?
update: see discuss at Why does withContext await for the completion of child coroutines
Kotlin coroutines provide an API that enables you to write asynchronous code. With Kotlin coroutines, you can define a CoroutineScope , which helps you to manage when your coroutines should run. Each asynchronous operation runs within a particular scope.
Use withContext when you do not need the parallel execution. Use async only when you need the parallel execution. Both withContext and async can be used to get the result which is not possible with the launch . Use withContext to return the result of a single task.
GlobalScope is a top level CoroutineScope that is operating as long as the application is alive. We usually use this when we want to launch a running task on application scope so that the task will remains alive until the app killed. Since it's alive along with application lifetime, GlobalScope is a singleton object.
The launch launches a new coroutine concurrently with the rest of the code, which continues to work independently. The async creates a coroutine and can return the result of the asynchronous task.
Formally, coroutineScope
is a special case of withContext
where you pass in the current context, avoiding any context switching. Schematically speaking,
coroutineScope ≡ withContext(this.coroutineContext)
Since switching contexts is just one of several features of withContext
, this is a legitimate use case. withContext
waits for all the coroutines you start within the block to complete. If any of them fail, it will automatically cancel all the other coroutines and the whole block will throw an exception, but won't automatically cancel the coroutine you're calling it from.
Whenever you need these features without needing to switch contexts, you should always prefer coroutineScope
because it signals your intent much more clearly.
coroutineScope
is about the scoped lifecycle of several sub-coroutines. It's used to decompose a task into several concurrent subtasks. You can't change the context with it, so it inherits the Dispatcher
from the current context. Typically each sub-coroutine will specify a different Dispatcher
if needed.
withContext
is not typically used to start sub-coroutines, but to temporarily switch the context for the current coroutine. It should complete as soon as its code block completes (as of version 1.3.2, this is actually still stated in its documentation). Its primary use case is offloading a long operation from the event loop thread (such as the main GUI thread) to a Dispatcher
that uses its own thread pool. Another use case is defining a "critical section" within which the coroutine won't react to cancellation requests.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With