Is there a document on the semantics of Rust's mpsc channels?
I understand that using Rust's std::sync::mpsc::channels, sending a message to a sender is not blocking and the receiver can recv() it anytime later. But, my question is that does the message get available on the receiver as soon as it is sent to the sender, i.e., does recv() return the message right after it is sent?
I don't believe this is documented. The problem is that this is OS threading - it'll probably run soon after, but there isn't any strict time guarantee on that.
There aren't any other factors, though. Like, there's no extra thread or anything that has to schedule the messages. So as soon as send() has returned, recv() should be able to pick up the message.
Edit: two other things:
First, if you're interested in getting better time and performance, crossbeam::channel might be worth taking a look at.
Second, if you're willing to rely on undocumented implementation details, mpsc uses Thread::unpark to wake threads up. This has different implementations on different platforms, but should generally equate to waking the OS thread up.
I'm no expert but it seems to me that even if the message were available to the receiver as soon as the transmitter has written it that says nothing about when the receiver starts acting on it.
Consider your system has 1000 async "threads" going on, all waiting for such messages. Potentially our particular receiver has to wait for messages to be processed by 999 other threads first before it is scheduled to run a gain and can digest it's message.
It's not clear to me how it would help to know the answer to your question? How would one observably tell the difference between a message getting stuck in some kind of message queue for a second and a message that was available immediately but was not handled for one second because other threads were executed first?
Unless of course we could assign priorities to threads, which I have never heard of.
P.S. Is "thread" still the right term for code running under an async executor?
I was assuming you were talking about Rust's mpsc channels. But I reread your post, and realized I missed the word "async". Rust's std doesn't have any async mspc channels though - so if you're reference to a different implementation, could you link it?
The task with the receiver will be immediately notified. Async Rust works by repeatedly swapping the currently running task on each thread, and these notifications are what your executor will use to decide what the next task should be.
That said, swapping can only happen at an .await, so if all the threads are busy with tasks that spend a long time without reaching and .await, the receiver will be prevented from running by those other tasks. This is what we mean when we say "you shouldn't block the thread".
Thank you @daboross and @ZiCog!
Sorry the word "async" in my post is confusing. My question is about std::sync::mpsc, by async I meant using std::sync::mpsc::channel, not std::sync::mpsc::sync_channel. So, yes we are dealing with real threads here.
@daboross: This all makes sense. Currently, I do not care about the performance, but my plan for the future is switching to crossbeam. Oh, I should check Thread::unpark, thanks!
Async/sync, makes no difference. Except now we have the operating system scheduler in the mix. It may well decide not to run your receiver thread for a long time. Depending on what other activity is going on in the machine.
Again, how could we tell the difference between a message taking a long time in delivery and a thread not handling a message for a long time because it is not scheduled?
Yes, the receiver thread can be scheduled and progress anytime after the message is available (if using recv(), which blocks the thread if there is no message available). My question was not about thread scheduling, I was just interested in the semantics of send() and recv() methods.
The difference is that if the message is available on the receiver right after send() returns, the receiver thread can be scheduled and progress right after that. On the other hand, if the message takes a while to be delivered, the receiver thread, even if scheduled, will be blocked by recv() until the message is available, which may yield to another thread.
This makes no difference in programs using std::sync::mpsc, but it may make a difference when metaprogramming to manage or control those programs.