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

igor.wojda

10/13/2023, 12:19 AM
Hey coroutine experts I have large amount of classes (
Layer1
) that are starting
Big chunk of work
on a single thread (
Layer2
) and then pass the result to another class (
Layer3
). Currently this chunk work is duplicated on each thread. I would like utilise coroutines to perform this
Big chunk of work
once on multiple threads and cache the result. Client class (
Layer
) can't use coroutines so these coroutines (
Layer2
) have to be a thread blocking call (Class no coroutines, nit suspended function). • When a new instance of class (
Layer1
) wants to start work and work is already in progress (
Layer2
) then this (
Layer1
) waits for the
work
to be completed (
Layer2
) before proceeding further (
Layer3
) (we can block thread for now) • When a new instance of class (
Layer1
) wants to start work and worj was already completed (on
Layer2
) then the result will be passed to following class
Layer3
will use cached result (existing
work
result) I imagine this is double with coroutines. Can anybody help me with writing this code?
e

ephemient

10/13/2023, 12:34 AM
you want something like this, perhaps? https://pl.kotl.in/nTdxUykN8
p

PHondogo

10/13/2023, 5:35 AM
Maybe invokeOnCompletion and start should be done only for job === result?
e

ephemient

10/13/2023, 6:22 AM
it's safe to call those multiple times
p

PHondogo

10/13/2023, 8:28 AM
Yes. But less performant
i

igor.wojda

10/13/2023, 9:23 AM
what exactly is less performant?
p

PHondogo

10/13/2023, 9:27 AM
You need to perform operations (wich implies memory bariers cause of syncronization aspect) every time. In case of put invokeOnCompletion and start in else clause it will be executed distinct per existing key.
👍 1
d

David Kubecka

10/14/2023, 4:00 AM
I'm currently learning coroutines, I have two questions regarding @ephemient solution: • I guess
job.cancel()
is there because atomocity of job vs result is not guaranteed. Is there any reason why not make it so, i.e.
val result = pending.computeIfAbsent(key) { scope.async(...) }
? • Why there's also GlobalScope in the coroutine scope alongside Dispatchers.IO?
e

ephemient

10/14/2023, 4:06 AM
no, it's there because
.computeIfAbsent
may re-run the block multiple times when there are concurrent writers
if you do it the way you wrote it, you may end up launching the same work more than once
since this is not following structured concurrency you should explicitly pass a scope
GlobalScope makes that obvious. of course you could use some other parent scope that you already have outside of the usages, this was just an example
d

David Kubecka

10/14/2023, 4:11 AM
because
.computeIfAbsent
may re-run the block multiple times when there are concurrent writers
I thought
ConcurrentHashMap
is there exactly to prevent concurrent block evaluations for the same key...
e

ephemient

10/14/2023, 4:23 AM
oh that's fair. I originally had a normal MutableMap but realized it wouldn't be safe without external synchronization
🆗 1
2 Views