Allan Wang
12/27/2018, 6:07 AMlaunch
to launch(<http://Dispatchers.IO|Dispatchers.IO>)
, then the loops each print 3 times. What’s going on here? In production, would I be expected to specify a different context if I want the loops to produce results? Was adding the loops in separate launches not enough?bdawg.io
12/27/2018, 6:10 AM@UseExperimental(ExperimentalCoroutinesApi::class)
instead of annotating your code with it directlybdawg.io
12/27/2018, 6:16 AMrunBlocking
it only uses the current thread for launch
(as opposed to launch(IO)
). So by the time either of the launch
coroutines start, you have already invoked send 1, 2, 3, AND close()
. Since the BroadcastChannel is now closed, once the `launch`es get their turn to execute there’s nothing for the for
loops inside of the `launch`es to actually loop over. Using the IO
dispatcher gave you more threads for the `launch`es and the send()
code to run in parallel which is how you were able to loop over the 3 items before the channel was closedAllan Wang
12/27/2018, 6:30 AMDone Thread[main @coroutine#1,5,main]
1 end Thread[main @coroutine#2,5,main]
2 end Thread[main @coroutine#3,5,main]
Doesn’t that mean they are already running in different threads? I thought the difference was that they will only use the threadpool within Dispatchers.Default
, which is why I added a sleep to give the other threads a chance to finishAllan Wang
12/27/2018, 6:32 AMrunBlocking(<http://Dispatchers.IO|Dispatchers.IO>)
with the same resultbdawg.io
12/27/2018, 4:13 PMmain
thread. Each coroutine has it’s own name though.
launch
, async
, etc inherits the same CoroutineContext in the current scope. In the case of runBlocking
with an EmptyCoroutineContext, it provides a scope that is bound to the single thread it was launched in.
Try doing c.close()
after your sleep
. Because your channel has a capacity larger than the 3
items you’re providing, the `send`s are immediately completing all the way through the close()
. It looks like you’re experiencing racesbdawg.io
12/27/2018, 6:21 PMsleep
to 10 seconds, you would see
Done
<wait for 10 seconds>
1 end
2 end
Is that correct?Allan Wang
12/27/2018, 7:11 PM@Test
@UseExperimental(ExperimentalCoroutinesApi::class)
fun channel() {
val c = BroadcastChannel<Int>(100)
runBlocking(<http://Dispatchers.IO|Dispatchers.IO>) {
launch(/*<http://Dispatchers.IO|Dispatchers.IO>*/) {
println("1 start ${Thread.currentThread()}")
for (i in c.openSubscription()) {
println("1 $i")
}
println("1 end ${Thread.currentThread()}")
}
launch(/*<http://Dispatchers.IO|Dispatchers.IO>*/) {
println("2 start ${Thread.currentThread()}")
for (i in c.openSubscription()) {
println("2 $i")
}
println("2 end ${Thread.currentThread()}")
}
c.send(1)
c.send(2)
c.send(3)
delay(2000)
println("Done")
c.close()
}
}
It always prints both starts, then done, then both ends. Sometimes, it will print the numbers as well. I changed sleep
to delay
, and 2 seconds is already plenty, so I’m not sure if it’s a race condition at that point.
I always thought that something like
launch(context) {
launch {
// action
}
}
was equivalent to
launch(context) {
launch(context) {
// action
}
}
but I guess notbdawg.io
12/27/2018, 7:17 PMrunBlocking(<http://Dispatchers.IO|Dispatchers.IO>) {...}
my output is 2 1
Done Thread[DefaultDispatcher-worker-1,5,main]
2 2
1 1
2 3
1 2
2 end Thread[DefaultDispatcher-worker-2,5,main]
1 3
1 end Thread[DefaultDispatcher-worker-3,5,main]
bdawg.io
12/27/2018, 7:18 PMAllan Wang
12/27/2018, 7:22 PM<http://Dispatchers.IO|Dispatchers.IO>
for all launches. I do expect it to work your way though, given the context isn't changingAllan Wang
12/27/2018, 7:33 PM