core: lazy realization is shared across walks (once-only effects); pmap family

Every walk over a lazy seq created FRESH wrapper tables around the shared
rest-thunks (ls-rest, ls-seq/ls-count, realize-for-iteration, the printers,
reduce — each had its own make-lazy-seq loop), so independent walks re-ran
the thunks: side effects duplicated, and a doall'd seq of futures was
re-spawned serially by the deref walk. Every walker now goes through
ls-rest-cached, which memoizes the rest wrapper on its node — thunks run
exactly once, as in Clojure. Costs ~10% on walk-heavy benches (the per-node
cache get/put — Clojure's LazySeq pays the same); net still -9% vs the
pre-linear-walks baseline. Three regression rows pin once-only effects and
value stability across walks.

On top of that: pmap/pcalls/pvalues (jolt-oeu) over the real-thread futures
— spawn-all-then-deref (the once-only fix is what makes the doall actually
mean that), snapshot semantics documented, multi-coll arity via the
canonical vector-zip. System/currentTimeMillis + nanoTime land as System
statics (the realtime clock — os/time is whole seconds, which quantized
every elapsed measurement to 1000ms). Seven pmap rows incl. a generous-
margin parallelism check (4 x 200ms sleeps under 700ms after warmup).
This commit is contained in:
Yogthos 2026-06-10 19:14:45 -04:00
parent 599c0468f7
commit 4a1a9e3aec
8 changed files with 78 additions and 12 deletions

View file

@ -191,6 +191,10 @@
(let [msg (if message message (str "Assert failed: " (pr-str x)))]
`(when-not ~x (throw (ex-info ~msg {})))))
;; (pvalues e1 e2 ...) — each expression evaluated in parallel (pcalls).
(defmacro pvalues [& exprs]
`(pcalls ~@(map (fn [e] `(fn [] ~e)) exprs)))
(defmacro delay [& body]
`(make-delay (fn [] ~@body)))

View file

@ -175,3 +175,17 @@
(lazy-seq
(when-let [s (seq coll)]
(cons (first s) (take-nth n (drop n s)))))))
;; --- pmap family (jolt-oeu): parallel map over real-thread futures ----------
;; Each element's work runs on its own OS thread with SNAPSHOT semantics
;; (futures marshal captured state — pure fns only, mutations don't propagate
;; back). All futures are spawned up front (doall), then derefed in order:
;; coarse-grained work only, as with Clojure's pmap.
(defn pmap
([f coll]
(map deref (doall (map (fn [x] (future (f x))) coll))))
([f coll & colls]
(pmap (fn [xs] (apply f xs)) (apply map vector coll colls))))
(defn pcalls [& fns] (pmap (fn [f] (f)) fns))