r4zzz4k
01/16/2018, 7:31 PMCompletableDeferred
, thank you very much for this suggestion!
Here's the final sample: https://try.kotlinlang.org/#/UserProjects/dsu5vhgcr0ls2h0flirmp3pf9g/ga94a9qaeq9e6v6s5bncbb75k3bj0
01/16/2018, 8:25 PMval dispatcher = newSingleThreadContext("dispatch")
val r1 = async(dispatcher) {
log("Command 1 started")
delay(1200)
log("Command 1 finishing")
"Command 1 result"
}.await()
log(r1)
val r2 = async(dispatcher) {
log("Command 2 started")
delay(300)
log("Command 2 finishing")
"Command 2 result"
}.await()
log(r2)
r4zzz4k
01/16/2018, 8:58 PMfixedThreadPool
and multiple `actor`s.bj0
01/16/2018, 9:08 PMactor
is a good way to make sure stuff is executed serially if you have any suspension, but usually you do the actual execution of the "command" inside the actor, not just launch it in async
and wait for it in the actor, that doesn't guarantee serializationr4zzz4k
01/16/2018, 9:28 PM.await()
in the `actor`'s body guarantees that the task is done before the next one is pulled in? async
coroutines that are sent to it are signalling response at their end, after the command body is executed, so from what I can see this should work. actor
awaits for the coroutine itself, post()
awaits for the CompletableDeferred
which is completed at the very end of the coroutine.bj0
01/16/2018, 9:45 PMLAZY
, I've never used that. For normal async {}
it will not be true if your command has any type of suspend, then other queue'd `async {}`'s could start during that suspensionr4zzz4k
01/16/2018, 10:01 PMasync
marked as LAZY
are actually run after the .await()
call (or .join()
/ .start()
) -- till that point they will just hang out there waiting to be started, exactly what I need.bj0
01/16/2018, 10:03 PMfun commandQueue(context: CoroutineContext) = actor<suspend () -> Unit>(context = context) {
log("Command queue started")
for (operation in channel)
operation()
log("Command queue finished")
}
suspend fun <T> SendChannel<suspend () -> Unit>.post(command: () -> T): Deferred<T> {
val completable = CompletableDeferred<T>()
this.send { completable.complete(command()) }
return completable
}
typealias
the function signature to make it look cleanerr4zzz4k
01/16/2018, 10:24 PMactor
runs within separate context and so are commands? Seems much cleaner, I agree. Will check that tomorrow as I'm already on my way home, thanks!
It's hard to switch to thinking in terms of neat concurrency of coroutines and channels after more than a year of C++ and dirty hand-managed parallelism :)
Thank you again for your help, much appreciated!bj0
01/16/2018, 10:49 PMnewSingleThreadContext
as CoroutineContext
to the actor
, the actor
will only run on that thread, which saves you from having to pass the dispatcher around to other places