Xo is experimental. The source code is not public yet; it will be soon. Read the release notes
Menu · Structured concurrency

Docs

Structured concurrency

concurrency/main.xo

fn square(n: Int) -> Int { n * n }

fn main(os: Os) {
  let sum = scope s {
    let a = s.spawn(fn() { square(3) })
    let b = s.spawn(fn() { square(4) })
    a.await + b.await
  }
  os.stdio.println("sum ${sum}")

  let ch = Chan[Int].new(cap: 8)
  let total = scope s {
    s.spawn(fn() {
      for i in 1..=5 { ch.send(i) }
      ch.close()
    })
    var t = 0
    for x in ch { t += x }
    t
  }
  os.stdio.println("total ${total}")
}

Output:

sum 25
total 15
  • scope s { ... } is an expression. s.spawn(f) starts a task inside it, and t.await waits for its result.
  • No task outlives its scope. When the body finishes, the scope waits for its tasks; when it fails or returns early, it cancels them and waits for them to unwind. There are no leaked goroutines to find later.
  • If a task fails, the scope cancels its siblings and the error propagates like ?.
  • Channels work as in Go: for x in ch receives until the channel is closed and drained, and select waits on several at once.
  • Deadlines and cancellation flow down the scope tree, so there is no ctx parameter to thread through every call.
  • xo test runs tasks on a deterministic scheduler, and xo test --explore=N searches other interleavings for a failing one.