kotlin coroutines, what is the difference between coroutineScope and withContext - kotlin-coroutines

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

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.

Related

Springboot coroutine bean scope or local scope

I have a requirement, where we want to asynchronously handle some upstream request/payload via coroutine. I see that there are several ways to do this, but wondering which is the right approach -
Provide explicit spring service class that implements CoroutineScope
Autowire singleton scope-context backed by certain defined thread-pool dispatcher.
Define method local CoroutineScope object
Following on this question, I'm wondering whats the trade-off if we define method local scopes like below -
fun testSuspensions(count: Int) {
val launchTime = measureTimeMillis {
val parentJob = CoroutineScope(Dispatchers.IO).launch {
repeat(count) {
this.launch {
process() //Some lone running process
}
}
}
}
}
Alternative approach to autowire explicit scope object backed by custom dispatcher -
#KafkaListener(
topics = ["test_topic"],
concurrency = "1",
containerFactory = "someListenerContainerConfig"
)
private fun testKafkaListener(consumerRecord: ConsumerRecord<String, ByteArray>, ack: Acknowledgment) {
try {
this.coroutineScope.launch {
consumeRecordAsync(consumerRecord)
}
} finally {
ack.acknowledge()
}
}
suspend fun consumeRecordAsync(record: ConsumerRecord<String, ByteArray>) {
println("[${Thread.currentThread().name}] Starting to consume record - ${record.key()}")
val statusCode = initiateIO(record) // Add error-handling depending on kafka topic commit semantics.
// Chain any-other business logic (depending on status-code) as suspending functions.
consumeStatusCode(record.key(), statusCode)
}
suspend fun initiateIO(record: ConsumerRecord<String, ByteArray>): Int {
return withContext(Dispatchers.IO) { // Switch context to IO thread for http.
println("[${Thread.currentThread().name}] Executing network call - ${record.key()}")
delay(1000 * 2) // Simulate IO call
200 // Return status-code
}
}
suspend fun consumeStatusCode(recordKey: String, statusCode: Int) {
delay(1000 * 1) // Simulate work.
println("[${Thread.currentThread().name}] consumed record - $recordKey, status-code - $statusCode")
}
Autowiring bean as follows in some upstream config class -
#Bean(name = ["testScope"])
fun defineExtensionScope(): CoroutineScope {
val threadCount: Int = 4
return CoroutineScope(Executors.newFixedThreadPool(threadCount).asCoroutineDispatcher())
}
It depends on what your goal is. If you just want to avoid the thread-per-request model, you can use Spring's support for suspend functions in controllers instead (by using webflux), and that removes the need from even using an external scope at all:
suspend fun testSuspensions(count: Int) {
val execTime = measureTimeMillis {
coroutineScope {
repeat(count) {
launch {
process() // some long running process
}
}
}
}
// all child coroutines are done at this point
}
If you really want your method to return immediately and schedule coroutines that outlive it, you indeed need that extra scope.
Regarding option 1), making custom classes implement CoroutineScope is not encouraged anymore (as far as I understood). It's usually suggested to use composition instead (declare a scope as a property instead of implementing the interface by your own classes). So I would suggest your option 2.
I would say option 3) is out of the question, because there is no point in using CoroutineScope(Dispatchers.IO).launch { ... }. It's no better than using GlobalScope.launch(Dispatchers.IO) { ... } (it has the same pitfalls) - you can read about the pitfalls of GlobalScope in its documentation.
The main problem being that you run your coroutines outside structured concurrency (your running coroutines are not children of a parent job and may accumulate and hold resources if they are not well behaved and you forget about them). In general it's better to define a scope that is cancelled when you no longer need any of the coroutines that are run by it, so you can clean rogue coroutines.
That said, in some circumstances you do need to run coroutines "forever" (for the whole life of your application). In that case it's ok to use GlobalScope, or a custom application-wide scope if you need to customize things like the thread pool or exception handler. But in any case don't create a scope on the spot just to launch a coroutine without keeping a handle to it.
In your case, it seems you have no clear moment when you wouldn't care about the long running coroutines anymore, so you may be ok with the fact that your coroutines can live forever and are never cancelled. In that case, I would suggest a custom application-wide scope that you would wire in your components.

Volley doesn't respond in suspense function [duplicate]

I have a suspend function that calls POST request to the server. I want to configure some text in the activity to show the information I received from the server.
suspend fun retrieveInfo():String
I tried calling inside onCreate, onResume but crashes runtime.
runBlocking {
retrieveInfo()
}
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.google.augmentedimage/com.google.AugmentedImageActivity}: android.os.NetworkOnMainThreadException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3086)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3229)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
Where am I suppose to put these suspend calls (in which part of lifecycle of activity)? Should I be using something other than runBlocking?
By default runBlocking runs the suspending code block in the thread runBlocking was called on.
So if you called runBlocking from the Activity callback your suspending block will be executed on the main thread, from which you cannot access network (query a server).
You need to switch a dispatcher in your coroutine block for that call. The simplest fix for your code would be to move the execution to the Dispatchers.IO.
runBlocking {
withContext(Dispatchers.IO) {
retrieveInfo()
}
}
That being said, I suggest two things (not related directly to your question):
Read Coroutines on Android (this part and the following ones)
2. Don't use runBlocking for your case, but define a correct job and use job.launch{}
If you want to write in activity:
class MyActivity : AppCompatActivity() {
private val scope = CoroutineScope(newSingleThreadContext("name"))
fun doSomething() {
scope.launch { ... }
}
}

Kotlin coroutines running sequentially even with keyword async

Hi guys i'm trying to improve performance of some computation in my system. Basically I want to generate a series of actions based on some data. This doesn't scale well and I want to try doing this in parallel and getting a result after (a bit like how futures work)
I have an interface with a series of implementations that get a collection of actions. And want to call all these in parallel and await the results at the end.
The issue is that, when I view the logs its clearly doing this sequentially and waiting on each action getter before going to the next one. I thought the async would do this asynchronously, but its not.
The method the runBlocking is in, is within a spring transaction. Maybe that has something to do with it.
runBlocking {
val actions = actionsReportGetters.map { actionReportGetter ->
async {
getActions(actionReportGetter, abstractUser)
}
}.awaitAll().flatten()
allActions.addAll(actions)
}
private suspend fun getActions(actionReportGetter: ActionReportGetter, traderUser: TraderUser): List<Action> {
return actionReportGetter.getActions(traderUser)
}
interface ActionReportGetter {
fun getActions(traderUser: TraderUser): List<Action>
}
Looks like you are doing some blocking operation in ActionReportGetter.getActions in a single threaded environment (probably in the main thread).
For such IO operations you should launch your coroutines in Dispatchers.IO which provides a thread pool with multiple threads.
Update your code to this:
async(Dispatchers.IO) { // Switch to IO dispatcher
getActions(actionReportGetter, abstractUser
}
Also getActions need not be a suspending function here. You can remove the suspend modifier from it.

How to understand order of calling coroutines with scope?

I saw the coroutines example here.
To understand the example I made three different examples with each scope.
The printed number is the following #N.
It's just my opinion, so if there is a wrong thing, let me know.
#1: 3->1->2->4
runBlocking {
launch {
println("1-Task from runBlocking")
}
coroutineScope { // Creates a coroutine scope
launch {
println("2-Task from nested launch")
}
println("3-Task from coroutine scope")
}
println("4-Coroutine scope is over")
}
I understood the coroutineScope waits until the children will be completed. The outer runBlocking has two coroutines.
The first is launch of 1 and the second is in coroutineScope.
The coroutineScope will be handled first based on the call stack.
Thus the first printed number is 3 because it's within regular function.
And then the 1 can be printed before 2.
The 4 will be printed after coroutineScope block is finished.
#2: 1->3->2->4
runBlocking {
launch {
println("1-Task from runBlocking")
}
runBlocking { // Creates a coroutine scope
launch {
println("2-Task from nested launch")
}
println("3-Task from coroutine scope")
}
println("4-Coroutine scope is over")
}
runBlocking is not suspend function that's why the outer runBlocking doesn't have a coroutine. Thus the 1 will be printed first. After that, the inner runBlocking has one coroutine so wait until this block will be finished. Thus 3 and 2 will be printed. Last, 4 printed after inner runBlocking.
#3: 2->4->3->1, 4->3->2->1, 4->2->3->1
runBlocking {
launch {
println("1-Task from runBlocking")
}
GlobalScope.launch { // Creates a coroutine scope
launch {
println("2-Task from nested launch")
}
println("3-Task from coroutine scope")
}
println("4-Coroutine scope is over")
}
There are several different results so I guessed it depends on environments on runtime.
But I wonder if it's impossible to print 1 first or not.
Second, how to understand scope in other suspend or scope.

Spring component with method invoked by several threads

I have the following component which is used by multiple threads since it is being invoked by a listener (Kafka consumer).
#Component
public class SampleClass {
private RuleFactory ruleFactory;
public SampleClass(RuleFactory ruleFactory) {
this.ruleFactory = ruleFactory;
}
void sampleFunction(final SampleObject sampleObject) {
ruleFactory
.getRules().stream()
.filter(ruleFilter -> ruleFilter.getPredicate().test(sampleObject))
.findFirst()
.ifPresent(caseWinner -> caseWinner.applyChanges().accept(sampleObject));
}
}
The method doesn't change the state of the class, but is shares another component the RuleFactory. Which doesn't have any mutable attributes.
Is this method thread safe ? An answer I got, was, it is not since you apply changes to an object which is passed as a parameter. Is this valid?
I can't think of any case other than two threads passing the same object and process it in parallel.
Should this method be synchronized? Is this final keyword useless in terms of thread safety?
The method is thread-safe if all of the following are true:
All of the ruleFactory methods called are thread safe, that is, none of them change internal state of ruleFactory.
ruleFilter and caseWinner are thread-safe
If another thread has a reference to sampleObject, then the state of sampleObject must not be modified.
You already said RuleFactory is thread safe.
If you modify sampleObject in this function and if another thread has reference to sampleObject, then there is a race condition. Synchronizing this function will only work if all the other threads are using the method of the same SampleClass instance to modify sampleObject. You can use sampleObject itself, but you have to make sure all other threads that access to sampleObject also use synchronize blocks:
synchronized(sampleObject) {
// read or write sampleObject
}

Resources