Crates.io | uringy |
lib.rs | uringy |
version | 0.5.0 |
source | src |
created_at | 2021-11-16 02:47:21.208317 |
updated_at | 2023-08-30 21:56:07.990117 |
description | A simple single-threaded concurrency runtime for Rust based on io_uring. |
homepage | https://github.com/Dennis-Krasnov/Uringy |
repository | https://github.com/Dennis-Krasnov/Uringy |
max_upload_size | |
id | 482457 |
size | 64,622 |
Writing concurrent code in Rust doesn't need to be painful. Uringy is a runtime that combines structured concurrency, a single-threaded design, and Linux's io_uring. Intended for server applications, from simple single-threaded to highly scalable thread-per-core designs.
async
/await
's limitations and footgunsSend
and non-'static
typesInstall Rust and create a new cargo project.
Add uringy as a dependency: cargo add uringy
Then replace src/main.rs
with:
// No need for async main
#[uringy::start]
fn main() {
let handle = uringy::fiber::spawn(|| tcp_echo_server(9000)); // No need for async block
uringy::signals().filter(Signal::is_terminal).next().unwrap();
uringy::println!("gracefully shutting down");
handle.cancel(); // Cancellation propagates throughout the entire fiber hierarchy
// Automatically waits for all fibers to complete
}
// No need for async functions
fn tcp_echo_server(port: u16) {
let listener = uringy::net::TcpListener::bind(("0.0.0.0", port)).unwrap();
uringy::println!("listening for TCP connections on port {port}"); // No need for .await
let mut connections = listener.incoming();
while let Ok((stream, _)) = connections.next() {
uringy::fiber::spawn(move || handle_connection(stream));
}
}
fn handle_connection(tcp: TcpStream) {
let (mut r, mut w) = stream.split();
let _ = std::io::copy(&mut r, &mut w); // TcpStream implements std::io's Read and Write
}
And run your project using: cargo run --release
If you're using macOS, use a Linux virtual machine or a docker container. If you're using Windows, use WSL.
For more, check out the examples directory.
There are currently no cargo flags.
std thread | uringy fiber | tokio task | |
---|---|---|---|
OS support | all | Linux | most |
IO interface | blocking | io_uring | epoll + thread pool |
function color | sync | sync | sync and async |
start | N/A | 27 μs | 27.5 μs (3.5 μs using current thread scheduler) |
spawn | 9828 ns | 59 ns | 907 ns (58ns using current thread scheduler) |
spawn Send bound |
yes | no | yes, unless using LocalSet |
spawn 'static bound |
yes, unless using scope | yes, unless using scope | yes |
stack size | virtual 8MB (configurable), 4KB increments | virtual 128KB (configurable), 4KB increments | perfectly sized |
stack limitations | may overflow | may overflow | can't use recursion |
context switch | 1405 ns | 60 ns | 1328 ns (308 ns using current thread scheduler) |
multi-tasking | preemptive | cooperative | mostly cooperative |
structured concurrency | no guarantees | parent fiber outlives its children | no guarantees |
runs until | main thread completes | all fibers complete | block_on completes |
parallelism | automatic | manual | automatic, unless using current thread scheduler |
userspace scheduler | N/A | minimal | work stealing |
cancellation | using esoteric unix signals | first class, voluntary | leaks memory, causes bugs |
The MSRV is 1.70.0 (released in June 2023).
Check your Rust version by running rustc --version
in a terminal.
The minimum kernel version is 6.1 (released in December 2022).
Check your kernel version by running uname -r
in a terminal.
Uringy is licensed under the MIT license. It's a permissive license, which basically means you can do whatever you want.