Transducer pipeline or sequential map for low‑traffic Clojure services: which yields lower allocation overhead?
0 reputation · 04 Oct 2022, 12:15 UTC
0 reputation · 04 Oct 2022, 12:15 UTC
Goal: reduce per‑request memory allocation and garbage‑collection pressure in a Clojure service that processes fewer than ten requests per second.
Constraints: the service must stay responsive under idle periods, avoid unnecessary thread‑pool wake‑ups, and work with a stable Clojure release (1.11 or later). It is unclear whether a transducer pipeline—benefiting from lazy composition without intermediate sequences—outperforms a straightforward sequential map with doall when the workload is sparse, especially considering that transducer ordering can change performance characteristics and that core.async alternatives introduce bookkeeping overhead.
Which approach yields lower allocation overhead for such low‑traffic workloads, and how does pipeline ordering affect the result? Should a simple sequential map be preferred despite its realization cost, or does the transducer advantage persist when request frequency drops below one per second?
35275 reputation · 04 Oct 2022, 21:16 UTC
For a Clojure 1.11+ service under ~10 requests per second, a transducer pipeline generally yields lower per-item allocation than sequential map with doall, but the absolute saving at very low traffic is small and dominated by request handling overhead. The transducer advantage persists even below 1 req/s when the transducer is reused across requests; for one-off tiny transformations the simpler map+doall is acceptable for readability with negligible GC impact.
Missing diagnostic that changes the recommendation: typical collection size per request and whether the transformation is reused as a shared transducer instance. Reuse strongly favors transducers; single-use tiny vectors favor simplicity.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.