Race
race runs an array of zero-arg functions concurrently and returns a future for the first to succeed (finish without throwing). That winner's return value becomes the race result.
std.async.race([fn, ...]) // → future
Basic usage
var winner = std.async.race([
fn() { std.async.sleep(50); return "slow" },
fn() { std.async.sleep(10); return "fast" },
])
print(std.async.await(winner)) // fast
The slower fibers keep running in the background until they complete, but their results are ignored.
When to use race
- Timeout pattern — race real work against a sleep:
var result = std.async.race([
fn() { return std.net.http_client().request({url: "http://slow.example"}).body },
fn() { std.async.sleep(2000); return "timeout" },
])
print(std.async.await(result)) // body or "timeout", whichever finishes first
- Hedged requests — fire the same request to two mirrors, take the first:
var w = std.async.race([
fn() { return std.net.http_client().request({url: "http://a.example/data"}).body },
fn() { return std.net.http_client().request({url: "http://b.example/data"}).body },
])
print(std.async.await(w))
Notes
- Each function in the array is
fn() { … }with no arguments. Capture what you need via globals or closure over globals (functions do not capture locals — see Overview). raceitself does not cancel losers — they run to completion in the background. If they have side effects (writes, sends), those still happen.- Errors: a race completes with the first function that returns successfully — throwing functions never win, even if they finish before a successful one. If a function throws, its error is discarded. Only when every function throws does the race fail:
awaitthen re-throwsAsync error: All race() functions threw exceptions.
See also
- Spawn & Await — keep all futures and await them all
- Patterns — fan-out vs race
- Errors — awaiting race errors