Derek Berner
07/09/2019, 1:06 PMwithContext
to launch
a bunch of `Job`s in that context, does that mean I don't have to explicitly join
all those jobs at the end of the block?dekans
07/09/2019, 1:11 PMwithContext() {...}
is a CoroutineScope
, it will persist until all its children are done.Derek Berner
07/09/2019, 1:35 PMDerek Berner
07/09/2019, 1:40 PMbdawg.io
07/09/2019, 8:16 PMGlobalScope.launch
when you're already inside of a CoroutineScope
2) .launch(content)
and then immediately doing withContext
using the same exact context. launch
is already a CoroutineScope. No need to immediately open a nested oneDerek Berner
07/09/2019, 9:03 PMDerek Berner
07/09/2019, 9:04 PMDerek Berner
07/09/2019, 9:06 PMGlobalScope.launch
makes it run as a daemon, right? So if a rogue consumer doesn't finish consuming, it won't block the runtime from exitingDerek Berner
07/09/2019, 9:07 PMCoroutineScope
receiver was part of an earlier attempt that I haven't gotten around to cleaning upDerek Berner
07/09/2019, 9:09 PMwithContext
... I think I was originally thinking I needed to wait around for all those `launch`es to finish so I could do some cleanupbdawg.io
07/09/2019, 9:25 PMlaunch {
launch { delay(100) }
launch { delay(200) }
launch { delay(300) }
}
That top-level job doesn't complete until all of the children jobs complete toobdawg.io
07/09/2019, 9:26 PMGlobalScope
just removes it from being properly tracked by structured hierarchy. If the JVM runtime exits, all GlobalScope
jobs will cancel tooDerek Berner
07/10/2019, 3:09 PMinterface TriplexChannel<I, out O> : SendChannel<I>, ReceiveChannel<O>, Closeable {
data class Error<I>(val input: I, val error: Throwable)
val errors: ReceiveChannel<Error<I>>
}
@ExperimentalCoroutinesApi
@UseExperimental(ExperimentalTypeInference::class)
fun <I, O> CoroutineScope.triplex(
context: CoroutineContext = EmptyCoroutineContext,
capacity: Int = Channel.RENDEZVOUS,
capacityOut: Int = capacity,
capacityErrors: Int = capacity,
@BuilderInference block: suspend SendChannel<O>.(I) -> Unit
): TriplexChannel<I, O> {
val channelIn = Channel<I>(capacity)
val channelOut = Channel<O>(capacityOut)
val channelErrors = Channel<TriplexChannel.Error<I>>(capacityErrors)
launch(context) {
for (value in channelIn) {
launch {
try {
channelOut.block(value)
} catch (e: Throwable) {
when (e) {
is Error -> throw e
else -> channelErrors.send(TriplexChannel.Error(value, e))
}
}
}
}
}.invokeOnCompletion { e ->
when(e) {
null -> {
channelOut.close()
channelErrors.close()
}
else -> {
launch { channelIn.close(e) }
launch { channelOut.close(e) }
launch { channelErrors.close(e) }
}
}
}
return object : TriplexChannel<I, O>,
SendChannel<I> by channelIn,
ReceiveChannel<O> by channelOut,
Closeable
{
override val errors = channelErrors
override fun close() {
launch {
channelIn.close()
}
}
}
}
Derek Berner
07/10/2019, 3:10 PMuse
Derek Berner
07/10/2019, 3:32 PMGlobalScope.triplex
works too now that I think about it.