Unsynchronized synchronization primitives for async Rust.
This crate provides a fairly simple set of synchronization primitives which
are explicitly !Send
and !Sync
. This makes them useful for use in
singlethreaded systems like [yew].
You can think of this as a modern replacement to the now-deprecated [futures::unsync] module.
!Send
/ !Sync
synchronization primitives?Having unsynchronized sync primitives might seem weird since they are largely used for inter-task communication across threads.
The need for such primitives increase as we are seeing more singlethreaded systems like [yew] mature and are receiving richer support for async programming. In order to make them as efficient as possible it's useful that they are written with unsynchronized systems and constraints in mind so that they don't have to make use of atomics and locks.
The overhead of synchronization in real systems should be minor because of the role channels play in typical applications and they are optimized for uncontended use. But unsynchronized code still has the ability to optimize better for both performance and size.
In one of my applications replacing the use of tokio::sync::oneshot
with
unsync::oneshot
reduced the size of the resulting binary by 30kb (10kb
when optimized with wasm-opt
). Synthetic benchmarks in this project hints
at the unsync channels being about twice as fast for optimized builds when
used inside of a [LocalSet].
I haven't dug too deep into the specifics of why this is, but as long as this is the case I'd like to have access to drop in replacements allowing someone to tap into these benefits.
Add the following to your Cargo.toml
:
toml
unsync = "0.1.1"
```rust use unsync::spsc::{channel, Sender, Receiver}; use std::error::Error; use tokio::task;
async fn receiver(mut rx: Receiver
while let Some(m) = rx.recv().await {
out.push(m);
}
out
}
async fn sender(mut tx: Sender
Ok(())
}
async fn run() -> Result<(), Box
let _ = task::spawn_local(sender(tx));
let out = task::spawn_local(receiver(rx)).await?;
let expected = (0..1000).collect::<Vec<u32>>();
assert_eq!(out, expected);
Ok(())
} ```