Same loop, twice the time
In my lab, changing a container's CPU limit from two CPUs to one almost doubled the time needed to process 200 records: 42.1 seconds became 83.6 seconds. These are medians from five runs of each configuration. The two-CPU version processed two records at once; the one-CPU version processed one. Both wrote all 200 records.
I think this kind of slowdown is easy to miss: the batch still finishes and every record gets written. Without a baseline for how long it should take, the extra waiting can look like ordinary service latency.
Each record needed three enrichment calls followed by a write to a system of record. I used this familiar pattern:
await Parallel.ForEachAsync(records, cancellationToken, async (record, ct) =>
{
await ProcessAsync(record, ct);
});
Why the default becomes one
Parallel.ForEachAsync without ParallelOptions allows at most Environment.ProcessorCount concurrent operations. Passing new ParallelOptions { CancellationToken = ct } leaves MaxDegreeOfParallelism at its initial value, -1. For ForEachAsync, that means ProcessorCount again with the default scheduler. Setting -1 explicitly does not remove the limit.
The cancellation-token-only options are what…