Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

kotlin coroutines, what is the difference between coroutineScope and withContext

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

like image 929
lannyf Avatar asked Jul 02 '19 19:07

lannyf


People also ask

What is CoroutineScope in Kotlin?

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.

What is withContext in Kotlin?

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.

What is the difference between GlobalScope and CoroutineScope?

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.

What is the difference between launch and async in Kotlin coroutines?

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.


1 Answers

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.

like image 186
Marko Topolnik Avatar answered Sep 19 '22 22:09

Marko Topolnik