You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
pmap is documented as multi-threaded but runs sequentially #948
The docs describe pmap as a multi-threaded parallel map, but it runs sequentially. ray_pmap_fn (src/ops/collection.c) returns ray_map_fn(args, n). The comment above it explains why: the VM is thread-local and evaluation is single-threaded. It says so since 949fd68, and since #125 it said "parallel not implemented yet".
The user-facing docs still promise parallelism:
docs/docs/language/functions.md and docs/docs/reference/all-functions.md: "Parallel map (multi-threaded, returns a list)".
docs/docs/language/math.md: "Like map but distributes work across threads for large inputs".
docs/docs/guides/analytics.md: "Use pmap for embarrassingly parallel work. It distributes a function across list elements using worker threads."
Reproduction
On dev 62d9bffa, release build, run as rayforce -c 8 pm.rfl:
(set work (fn [k] (do (set acc 0) (set i 0)
(while (< i 300000) (set acc (+ acc (* i k))) (set i (+ i 1))) acc)))
(println (timeit (map work (til 8)))) ; 869.8 ms
(println (timeit (pmap work (til 8)))) ; 845.3 ms
The two take the same time, and pmap uses one core.
Expected
At least: the docs say what pmap does: a sequential alias for map that marks intent. They should also say where Rayforce does run in parallel: inside builtins and the query engine, over morsels, for vectors of at least RAY_PARALLEL_THRESHOLD elements. Otherwise users pick pmap for work it cannot speed up.
As a feature, if you want it: real parallel evaluation of independent lambda calls. Several restricted designs would already help, for example worker VMs that see globals read-only and return only values.
Use case
A backtest parameter sweep: many independent runs of the same Rayfall engine, one per configuration. Each run is an interpreted time loop over small per-instrument vectors (100–500 elements), so morsel parallelism never applies. The whole sweep therefore runs on one core.
Today the workaround is several processes. A coordinator .ipc.posts a job to each of several rayforce -p workers, then collects the results with .ipc.send. With 4 workers, the same work went from 1,818 ms to 438 ms (4.1×) with identical results. That works, but each worker loads the data again and holds its own copy in memory.
Confirmed the source contract at 62d9bff: ray_pmap_fn directly calls ray_map_fn, whose callback loop is sequential. I took the documentation correction only, covering the reference, math guide and analytics recommendation; real parallel lambda evaluation remains a separate design, not an implied existing capability.
I'll also distinguish callback scheduling from eligible builtin/query kernels inside a callback: those may use the pool independently. A large input or -c 8 doesn't by itself parallelize the map/pmap calls, and there isn't one universal threshold for every operator. I haven't independently rerun your timings or process-memory comparison.
Documentation landed via #949 → d4899d91 on dev, after independent review of 87b49bc5 and eleven successful checks; complete checked/landed tree matched. Strict MkDocs/anchors and the attributed pmap3/3/value examples passed. This changes five Markdown files, not callback scheduling: real parallel lambda evaluation remains separate, and I have not independently repeated the timing/memory claims.
Activity
morsel-ray commentedon Oct 22, 2026
Confirmed the source contract at 62d9bff:
ray_pmap_fndirectly callsray_map_fn, whose callback loop is sequential. I took the documentation correction only, covering the reference, math guide and analytics recommendation; real parallel lambda evaluation remains a separate design, not an implied existing capability.I'll also distinguish callback scheduling from eligible builtin/query kernels inside a callback: those may use the pool independently. A large input or
-c 8doesn't by itself parallelize themap/pmapcalls, and there isn't one universal threshold for every operator. I haven't independently rerun your timings or process-memory comparison.Documentation landed via #949 →
d4899d91ondev, after independent review of87b49bc5and eleven successful checks; complete checked/landed tree matched. Strict MkDocs/anchors and the attributed pmap3/3/value examples passed. This changes five Markdown files, not callback scheduling: real parallel lambda evaluation remains separate, and I have not independently repeated the timing/memory claims.