Start here. This is the direct spoken answer to practice first.
Why this question matters
Compare Parallel.ForEachAsync and Task.WhenAll for processing collections with async work and controlled concurrency. It matters in real backend work because load, cancellation, retries, and dependency latency decide whether the API stays predictable under pressure. The practical angle is parallel processing, bounded concurrency, collection processing, async I/O, CPU work, and dependency protection, tied to a concrete production decision.
Task.WhenAll is good when I have a known set of tasks and I am comfortable starting them all. Parallel.ForEachAsync is useful when I process a collection and want built-in control over degree of parallelism. If I have thousands of items, starting thousands of tasks at once can be risky. A bounded parallel loop can protect dependencies and memory. I would keep cancellation, cleanup, and bounded concurrency in the answer, because async code that works in a demo can still overload a real service.