gh123man / Async-Channels

Channels for Swift concurrency
MIT License
101 stars 5 forks source link

sync send method #11

Open xlc opened 12 hours ago

xlc commented 12 hours ago

Can we have a send method that is not async that only does nonBlockingSend and return false if that failed due to buffer full?

Use case: I am working with a C networking library. When it received data, my callback is called, and I am doing

Task {
    await channel.send(data)
 }

and when the buffer is full, the back pressure essentially goes to the dispatch queue, which is not what I wanted. If there is a sync send that fails when buffer is full, then I can tell the networking library to close the connection and notify upstream.

I noted there is a count method so I can inspect it and implements the back pressure correctly, but still with async send, there is still some unnecessary overheads.

I can make a PR if needed.

gh123man commented 10 hours ago

Hey, thanks for reaching out!

You can get the same effect as non blocking send by using select:

Task {
    await select {
        send("b", to: b)
        none { // called if send is not ready }
    }
}

In this case, the task will never block waiting to send. Does this cover your use case? If not I am happy to work together to find the right API.

xlc commented 9 hours ago

Unfortunately I am dealing with C callback here so no async/await allowed. I would like to return an error code when buffer is already full from the callback, which will indicate the library the data is not processed.

gh123man commented 9 hours ago

Unfortunately I am dealing with C callback here so no async/await allowed.

Given the existing solution you shared - are you able to call that code? Since it also includes an async function as well wrapped in a task.

Conceptually you could also do this:

if channel.count < maxSize {
     Task {
        await channel.send(data)
     }
} else {
    // channel full
}

This would generally prevent you from stacking back pressure on the dispatch queue (assuming there are not competing threads writing to the channel).

xlc commented 8 hours ago

Yes that will work. In my case there is only a singe writer and single reader. But I still think a sync API will be nice. For example, send in Rust channel is sync: https://doc.rust-lang.org/std/sync/mpsc/struct.Sender.html#method.send