Real OS threads: parallel map-reduce

parallel_map(items, "func_name") spawns one real OS thread per item (via Rust's std::thread::scope) and runs func_name(item) on each concurrently โ€” genuine parallelism, mirrored byte-for-byte into the compiled-native runtime (codegen.rs and its self-hosted twin runtime_rs.patlang), so it works whether interpreted, compiled via pat --patc, or compiled via the self-hosted patc1.exe. This demo counts primes below 200,000 by splitting the range into 8 chunks, counting each chunk's primes on its own thread (the MAP step), then summing the per-chunk counts sequentially (the REDUCE step) โ€” the classic map-reduce shape.

PatLang source
# Real OS-thread parallelism: parallel_map(items, "func_name") spawns one
# real std::thread per item (via std::thread::scope -- see
# ir/interpreter.rs and codegen.rs's own parallel_map, byte-for-byte
# mirrored into self_hosting/lib/runtime_rs.patlang for patc1.exe), and
# runs func_name(item) on each concurrently. This is genuine parallelism,
# not a simulation -- distinct from fibers (fiber_demo.patlang), which are
# cooperative and never actually run at the same time.
#
# Classic map-reduce shape: parallel MAP step, sequential REDUCE step.

make a function called is_prime takes n returns r
  if n < 2 then
    return false
  end
  let i = 2
  while (i * i) <= n do
    if (n % i) == 0 then
      return false
    end
    let i = i + 1
  end
  return true
end

# The "work" each thread does: count primes in its own slice of the range,
# expensive enough (a naive O(sqrt n) primality test per candidate) that
# real parallelism actually matters for wall-clock time, not just as a toy.
make a function called count_primes_in_range takes bounds returns r
  let lo = bounds[0]
  let hi = bounds[1]
  let count = 0
  let n = lo
  while n < hi do
    if is_prime(n) then
      let count = count + 1
    end
    let n = n + 1
  end
  return count
end

let chunk_size = 25000
let num_chunks = 8
let chunks = []
let c = 0
while c < num_chunks do
  let lo = c * chunk_size
  let hi = lo + chunk_size
  let chunks = list_push(chunks, [lo, hi])
  let c = c + 1
end

let t0 = now_ms()
let counts = parallel_map(chunks, "count_primes_in_range")
let t1 = now_ms()

# Sequential reduce: sum the per-chunk counts.
let total = 0
let i = 0
while i < counts.length do
  let total = total + counts[i]
  let i = i + 1
end

print("primes below " + (num_chunks * chunk_size) + ": " + total)
print("parallel_map across " + num_chunks + " real OS threads: " + (t1 - t0) + " ms")

Native run on the build machine (real OS threads, patc1.exe-compiled):

primes below 200000: 17984
parallel_map across 8 real OS threads: 611 ms

No real "run in browser" button: the WASM sandbox this playground runs in has no OS-level threading support (wasm32-wasip1 without the threads proposal), so parallel_map has no backing implementation there. The animation below is a purely illustrative, non-functional mock โ€” plain JavaScript staggering 8 boxes with fake timing to show the SHAPE of the real run above, not a live computation. The numbers it displays are the real transcript's own numbers, baked in statically.

Simulated (not live โ€” see note above):