Pihentagy
06/13/2023, 2:50 PMkotlinx.coroutines.async?
I have now:
dependencies {
implementation ("org.jetbrains.kotlin:kotlin-stdlib")
implementation ("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$coroutinesVersion")Joffrey
06/13/2023, 2:51 PMkotlinx-coroutines-core is enoughJoffrey
06/13/2023, 2:52 PMkotlin-stdlibJoffrey
06/13/2023, 2:53 PMkotlinx-coroutines-jdk8 dependency (which was merged with the core)Joffrey
06/13/2023, 2:54 PMkotlin-reflect, it depends on whether something else in your project needs itPihentagy
06/13/2023, 2:58 PMUnresolved reference: async
for the line
val auctionAssetInfoDeferred = kotlinx.coroutines.async {
when I do a gradle clean buildPihentagy
06/13/2023, 3:01 PMval coroutinesVersion = "1.7.0"
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")Joffrey
06/13/2023, 3:05 PMasync cannot be used this way, though. If you check the documentation of this function, you'll see that it requires a CoroutineScope as receiver.
You need to add an import kotlinx.coroutines.async at the top of your file, and then just use async { ... } (unprefixed) in a place where a CoroutineScope is in context, or scope.async { ... } where scope is a CoroutineScope.
Using a fully qualified name with the kotlinx.coroutines. prefix doesn't work if the function expects a receiver (I guess that's a syntax limitation).Pihentagy
06/13/2023, 3:11 PMJoffrey
06/13/2023, 3:13 PMsuspend fun runTasksInParallel(): SomeResult = coroutineScope {
val deferredResult1 = async { task1() }
val deferredResult2 = async { task2() }
SomeResult(deferredResult1.await(), deferredResult2.await())
}
Or if you're not using coroutines anywhere else and you want a blocking call rather than a suspend function:
fun runTasksInParallel(): SomeResult = runBlocking(Dispatchers.Default) {
val deferredResult1 = async { task1() }
val deferredResult2 = async { task2() }
SomeResult(deferredResult1.await(), deferredResult2.await())
}
Or use launch instead of async if you don't need the results:
fun runTasksInParallel() = runBlocking(Dispatchers.Default) {
launch { task1() }
launch { task2() }
}Pihentagy
06/13/2023, 3:16 PMJoffrey
06/13/2023, 3:18 PM<http://Dispatchers.IO|Dispatchers.IO>Pihentagy
06/13/2023, 3:20 PMJoffrey
06/13/2023, 3:25 PMGlobalScope.async { ... } and deferred.await() in Kotlin (I had written this comparison a while ago if that helps you).
Note that using GlobalScope is regarded as a bad idea in Kotlin because of this problem. It escapes the safety of structured concurrency. You basically start coroutines flying around without making sure they don't hang (and thus leak) forever, or this kind of things.Joffrey
06/13/2023, 3:27 PMcoroutineScope { ... } to give some sort of lifetime to the async work we startPihentagy
06/13/2023, 3:29 PMfun runTasksInParallel(): SomeResult = runBlocking(Dispatchers.Default) {
val deferredResult1 = async { task1() }
val deferredResult2 = async { task2() }
SomeResult(deferredResult1.await(), deferredResult2.await())
}Joffrey
06/13/2023, 3:34 PMSo having a GlobalScope is something like a global lock?Not really, it doesn't help synchronizing anything actually. It's more of a "no scope" equivalent. A scope in Kotlin coroutines can be seen as a way to delimit the lifetime of the coroutines that you launch in it (it acts as a parent, and allows to cancel all child tasks in bulk for instance). The
GlobalScope doesn't act as a parent, it doesn't keep track of children, it doesn't allow to cancel children in bulk. It's sort of an escape hatch for very narrow use cases.
So, to just parallelize one function, your second approach is a good startYeah that is a good start.
runBlocking basically blocks the calling thread while waiting for all child coroutines to finish, and provides a coroutine scope that delimits their lifetime. You know that, when this runBlocking call returns, all child coroutines have completed in some way (and thus cannot leak).
coroutineScope is the equivalent of runBlocking, but it suspends the calling coroutine instead of blocking the calling thread. So it requires you to be already inside the coroutines world (because it's marked as suspend itself).Joffrey
06/13/2023, 3:36 PMPihentagy
06/13/2023, 3:49 PMJoffrey
06/13/2023, 3:50 PMJeff Lockhart
06/13/2023, 4:07 PMasync without a CoroutineScope receiver. This was before the API became stable and requires this to enforce structure concurrency. So if you really have a use case to have your async work run with an unbounded scope, you explicitly use GlobalScope to declare this intent.
I recommend reading Roman's blog post about structured concurrency. He has many good posts on the topic of coroutines: https://elizarov.medium.com/Jeff Lockhart
06/13/2023, 4:12 PM