Spawn & Await
spawn starts a function now on the fiber pool and returns a future. await reads that future's result, suspending the caller until it completes (and re-throwing any error as Async error: …).
Reference
std.async.spawn(fn[, args...]) // run fn(args...) now → future
std.async.await(future) // → result or throws Async error
spawn copies its args by value (deep copy, like assignment). Use globals or ref aliasing if the task must see live shared state (see Overview and Types).
Basic usage
var f = std.async.spawn(fn() { return 42 })
print(std.async.await(f)) // 42
var g = std.async.spawn(fn(a, b) { return a + b }, 10, 20)
print(std.async.await(g)) // 30
await may be called from the main script or from another fiber — it always yields until the target completes.
Why spawn — overlapping work
The point is concurrency: spawned tasks run on the same worker pool and overlap while the caller waits. Compare serial vs concurrent for three 300 ms jobs:
var job = fn(name) { std.async.sleep(300); return name }
// serial — 900 ms (one finishes before the next starts)
var t0 = std.time.now()
job("a"); job("b"); job("c")
print("serial: ", std.time.elapsed(t0), "ms") // e.g. 902 ms
// concurrent — ~300 ms (all three overlap)
var t1 = std.time.now()
var f1 = std.async.spawn(job, "a")
var f2 = std.async.spawn(job, "b")
var f3 = std.async.spawn(job, "c")
var results = [std.async.await(f1), std.async.await(f2), std.async.await(f3)]
print("concurrent:", std.time.elapsed(t1), "ms", results) // e.g. 301 ms ["a","b","c"]
Use this whenever you have independent I/O — fetching several HTTP endpoints, processing several files, or running parallel std.time.timer work.
Full fan-out example with HTTP (all fetches overlapped):
var urls = ["https://a.example/1", "https://b.example/2", "https://c.example/3"]
var futures = []
for (u : urls) {
futures:insert(std.async.spawn(fn(u) {
return std.net.http_client().request({url: u}).body
}, u))
}
var bodies = []
for (f : futures) { bodies:insert(std.async.await(f)) } // parallel
Future lifecycle
- A future is ready after the fiber returns or throws. Awaiting consumes it: a second
awaiton the same future throwsINVALID_OPERAND_TYPE("Future not found or already awaited"). - Awaiting discards the future, so don't
awaita future you still need to pass around. If you need to read a value more than once, copy it out of the result first. - There is no
cancelforspawned futures — if you need cancellable work use Defer orstd.time.timerwithcancel(). racereturns a future for the winner — see Race.