So excited to see where these new async algorithms go! I've been playing around with them and wondering about a tweaked case of this example in the docs.
let channel = AsyncChannel<String>()
Task {
while let resultOfLongCalculation = doLongCalculations() {
await channel.send(resultOfLongCalculation)
}
await channel.finish()
}
for await calculationResult in channel {
print(calculationResult)
}
How would the sender of channel values know that the listener has stopped listening? For instance, what if the for
loop looked like this
for await calculationResult in channel {
if weGotEnough { break }
// ....
}
In this case we have a condition that leaves the loop early. But the sender of the channel has already started awaiting on the send()
operation and is now just sitting there. Could there some way to signal back that the listening is done? Even if we kept around some sort of Task
to cancel or even another Channel
that signals that we're done that the sender can listen to, it seems that once the await channel.send()
happens, the task is effectively blocked until someone asks for the result.
Take this example...
let channel = AsyncChannel<Int>()
let task = Task {
print("awaiting")
await channel.send(1)
print("done sending")
}
try! await Task.sleep(nanoseconds: 1_000_000_000)
task.cancel()
print("cancelled task")
This outputs:
awaiting
cancelled task
And the await
within the task never returns. This is an easy footgun for leaking tasks.
It seems like Channel.send
should be throwing
so that a cancellation of the outer task would make sure we don't leak like this.