https://kotlinlang.org logo
#coroutines
Title
# coroutines
s

svenjacobs

02/14/2020, 8:39 AM
What is the best approach of starting a long running computation inside a
CoroutineScope
that keeps on running even if the scope is cancelled and if another (new) scope is accessing the same function/computation, the already computed value should be returned? Sounds like a job for a
ConflatedChannel
, right? I tried something with
Deferred
but the code (test code!!) is far from beautiful:
Copy code
var result: Deferred<Int>? = null

fun longComputationAsync(): Deferred<Int> {
    result = result ?: GlobalScope.async {
        println("longComputation")
        delay(1000)
        1337
    }
    return result!!
}

val scope1 = CoroutineScope(Dispatchers.Default)
scope1.launch {
    println("scope 1")
    println(longComputationAsync().await())
}
scope1.cancel()

val scope2 = CoroutineScope(Dispatchers.Default)
val job = scope2.launch {
    println("scope 2")
    println(longComputationAsync().await())
}

runBlocking {
    job.join()
}
m

Matej Drobnič

02/14/2020, 8:40 AM
You don't need the channel
If you just return one value, Deferred will be enough
However in your case, you are creating longComputationAsync twice
so two coroutines do not share same computation
s

svenjacobs

02/14/2020, 8:42 AM
I'm storing
result
in the outer scope so that
Deferred
should be shared, right? This is just a simulation of a singleton object which might do the computation.
s

svenjacobs

02/14/2020, 9:09 AM
This is an interesting question but the
NonCancellable
solution for instance is not what I actually need. Using
NonCancellable
would mean that the computation is finished in
scope1
however in my use case the result should land in
scope2
u

uli

02/14/2020, 9:10 AM
Copy code
import kotlinx.coroutines.*

val result by lazy { longComputationAsync() }

fun longComputationAsync(): Deferred<Int> {
    return GlobalScope.async {
        println("longComputation")
        delay(1000)
        1337
    }
}

val scope1 = CoroutineScope(Dispatchers.Default)
scope1.launch {
    println("scope 1")
    println(result.await())
}
scope1.cancel()

val scope2 = CoroutineScope(Dispatchers.Default)
val job = scope2.launch {
    println("scope 2")
    println(result.await())
}

runBlocking {
    job.join()
}
👍🏼 1
2 Views