Reputation: 5081
I have a case where I want to construct a ReceiveChannel
using produce
, asynchronously, but it's hanging. Here's a simplified example:
runBlocking {
val deferredChannel = async {
produce<String> { send("foo") }
}
val channel = deferredChannel.await()
println("Got channel")
val value = channel.receive()
println("Got value $value")
}
Neither println
is hit. It's plausible that there's some kind of coroutine deadlock going on, but I'm not not clear where/how.
How can I produce a ReceiveChannel
asynchronously?
Edit: It works if I change produce
to produce(capacity = 1)
, but why is that? Shouldn't the await()
succeed, at least, regardless of the producer's capacity? And what if I want to keep capacity=0?
Upvotes: 2
Views: 78
Reputation: 7838
It works if I change produce to produce(capacity = 1), but why is that? Shouldn't the await() succeed, at least, regardless of the producer's capacity?
Checking the docs on the produce()
method you call, and specifically the docs on the capacity parameter and Channel
we have (emphasis mine):
When capacity is 0 – it creates RendezvousChannel. This channel does not have any buffer at all. An element is transferred from sender to receiver only when send and receive invocations meet in time (rendezvous), so send suspends until another coroutine invokes receive and receive suspends until another coroutine invokes send.
This could be the reason why it's hanging. You are calling send
on your async
thread and then await
for it... however, as the docs say, no other co-routine has invoked receive
yet... so it will suspend until that happens and in this case it hangs.
Checking that same link on Channel, we also see why giving it a number greater than 0 solves this (emphasis mine):
When capacity is positive, but less than UNLIMITED – it creates array-based channel with given capacity. This channel has an array buffer of a fixed capacity. Sender suspends only when buffer is full and receiver suspends only when buffer is empty.
Upvotes: 1