go
A runtime-agnostic, Go-style concurrency library for Rust.
go gives you the concurrency primitives you reach for in Go — goroutine-style
task spawning, channels, select, a WaitGroup, timers, and singleflight —
on top of async/await, with the async runtime chosen at compile time.
Why
- Familiar. If you know Go's
go,chan,select, andsync.WaitGroup, you already know this API. - Runtime-agnostic. Write your code once and pick the runtime
(
tokio,async-std, orsmol) with a Cargo feature. Exactly one backend must be enabled — a missing or ambiguous choice is a compile error, not a runtime surprise. - Small surface. Thin, well-tested wrappers over
async-channelandevent-listener; no heavyweight abstractions.
Installation
[]
= { = "0.1", = ["rt-tokio"] } # or rt-async-std, rt-smol
rt-tokio is the default, so go = "0.1" selects Tokio. To use a different
runtime, disable defaults:
= { = "0.1", = false, = ["rt-async-std"] }
Requires a Rust toolchain with edition 2024 support.
Quick start
use Duration;
async
Primitives
Spawning — spawn / go!
// These are equivalent.
let h1 = spawn;
let h2 = go!;
assert_eq!;
Awaiting the returned JoinHandle yields Result<T, JoinError>; a panicking
task is reported as JoinError::Panic. Dropping the handle detaches the task
(it keeps running), matching goroutine semantics.
Channels — chan
let = bounded; // or go::chan::unbounded()
tx.send.await.unwrap;
assert_eq!;
Sender/Receiver are clonable MPMC handles re-exported from async-channel.
Multiplexing — select!
Wait on the first of several channel receives to complete, with an optional
non-blocking default branch:
select!
Supports up to three receive branches plus the optional default.
Waiting for a group — WaitGroup
let wg = new;
for i in 0..4
wg.wait.await; // returns once every task has called done()
wg.guard() returns a guard that calls done() automatically when dropped.
Timers — sleep / timeout
use Duration;
sleep.await;
match timeout.await
Deduplicating work — singleflight
Ensure only one execution is in flight for a given key; concurrent callers share
the single result (à la Go's golang.org/x/sync/singleflight).
let group = new;
// If many tasks call this concurrently with the same key, the closure runs
// once and every caller gets a clone of that one result.
let = group
.do_
.await;
// `shared` is true if the value was shared with at least one other caller.
Also provides do_chan (run the work on the runtime and receive the result over
a channel) and forget (evict an in-flight key so the next call re-executes).
If the leader's future is cancelled or panics before producing a value, the
in-flight call is abandoned and waiting callers retry — no caller hangs.
Runtime selection
| Feature | Backend |
|---|---|
rt-tokio |
tokio |
rt-async-std |
async-std |
rt-smol |
smol |
Enable exactly one. The crate emits a compile_error! if none or more than one
is selected, so misconfiguration fails fast at build time.
License
Licensed under either of
- Apache License, Version 2.0
- MIT license
at your option.