Hey coroutine experts I have large amount of class...
# coroutines
i
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
you want something like this, perhaps? https://pl.kotl.in/nTdxUykN8
p
Maybe invokeOnCompletion and start should be done only for job === result?
e
it's safe to call those multiple times
p
Yes. But less performant
i
what exactly is less performant?
p
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
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
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
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
oh that's fair. I originally had a normal MutableMap but realized it wouldn't be safe without external synchronization
🆗 1