Fetch 4 at a time, results in order
Requirement
Fetch eight user profiles whose response times differ, keeping at most 4 requests in flight at once — and print the results in source order (user 1 first), plus the maximum observed in-flight count as proof of the bound. The delays are in the code; both versions must print the lines shown under Expected output.
Expected output
user#1 user#2 user#3 user#4 user#5 user#6 user#7 user#8 max in flight: 4
Side by side
RxDart
FxDart
Why they differ
Both sides bound the concurrency in one operator, and the shared
counter shows both genuinely hit 4 in flight. The split is over
order. flatMap(maxConcurrent: 4) is a merge: it
emits each inner result the moment it completes, so with these delays
user 7 (10 ms) would print before user 1 (80 ms). To meet
the requirement the RxDart side tags every result with its id,
collects everything, and sorts afterwards — the ordering the source
had is destroyed by the merge and must be rebuilt by hand at the end.
mapConcurrent(4, fetch) never loses the order in the
first place. In a pull pipeline, concurrency is a property of
demand, not of delivery: the operator issues four overlapping
pulls but hands results downstream in the order they were asked for,
holding a fast late arrival until its slower predecessors are out.
Bounded-and-ordered is the shape most batch work actually wants —
results lined up with inputs, rate limits respected — and it is the
default here rather than a reconstruction. When completion order is
what you actually want, that exists too — concurrentPool,
the next example — but it is the variant you opt into, not the
behavior you undo.
Benchmark
Async case: the headline scale is N = 10,000, not 1,000,000. Every element costs an event-loop turn on both sides, so a million real awaits would measure Dart's event loop for minutes — not the pipeline. Delays are zero-length and the example's concurrency limit is kept; what the bars compare is the pipeline machinery.
N = 100
Time Tie
Peak memory Tie
N = 10,000
Time FxDart wins
Peak memory FxDart wins
Bars are medians of repeated timed iterations in fresh processes per side (small N is batched for timer resolution). Sides within 5% of each other — or within 0.6 ms, a difference no person can perceive — count as a tie; close relative races are re-measured up to 5 runs. In an app, anything under a few milliseconds is invisible to the user regardless of which bar is shorter. Memory is peak process RSS. The Dart VM and the dataset are identical on both sides, so the difference between the two bars is what the pipeline itself holds onto.