How many jobs can Parallel.For run?
Parallel.For accepts any number of items. It does not make a thread per item. It partitions the input into chunks and queues them on the thread poolThe thread poolA set of reusable worker threads that take jobs from a queue.Opens in a new tab. By default the runtime decides how many run at once, which for CPU-bound work is close to the core count, since more would only add context switching.
MaxDegreeOfParallelism caps it, to leave cores free or to bound a resource such as database connections.
var options = new ParallelOptions { MaxDegreeOfParallelism = 4 };Parallel.For(0, 10_000_000, options, i => DoWork(i));I/O-bound work
Parallel.For is for CPU-bound work. A blocking call in it leaves each thread waiting, so concurrency stays near the core count.
Parallel.For(0, 10000, i =>{ var result = httpClient.GetStringAsync(url).Result; // blocking!});For many I/O operations, Task.WhenAll with async delegates keeps thousands in flight on a few threads (see task combinatorsTask combinatorsWait for all of several tasks, or just the first one to finish.Opens in a new tab).
var tasks = urls.Select(url => httpClient.GetStringAsync(url));
var results = await Task.WhenAll(tasks); // thousands of concurrent requests, no threads blocked waiting
Where it matters
What limits it is core count for CPU work, thread pool growth for bursts of blocking work, memory per queued item, and external limits such as database connections or API rate limits. See fan-out and fan-inFan-out and fan-in with Parallel.ForRender independent items on all cores, keep the results in order, then merge them one at a time.Opens in a new tab.