C# Loops — From `for` and `foreach` to CPU Pipelines and LLM‑Ready Code
Source: Dev.to
Introduction
Most developers use loops every day.
Very few truly understand what happens below the syntax.
- Why does one
forloop fly while another crawls? - Why can
foreachbe free… or secretly expensive? - Why does the same loop get faster after it runs for a while?
- How can understanding loops help you write LLM‑friendly, performance‑predictable code?
This article is a mental‑model upgrade — from beginner syntax to processor‑level reality, modern .NET JIT behavior, and how to reason about loops like a scientist.
If you can write for (int i = 0; i Memory beats syntax every time.
3. Roslyn vs JIT — Who Does the Work?
| Stage | What it does |
|---|---|
| Roslyn (C# compiler) | Emits IL, lowers foreach, inserts branches |
| RyuJIT (runtime) | Generates machine code, removes bounds checks, hoists invariants, specializes hot loops, uses tiered compilation + PGO |
The same loop may be re‑compiled after warming up, which is why micro‑benchmarks need a warm‑up phase.
4. for, while, do/while — Real Differences
| Loop type | Key difference |
|---|---|
while | Condition evaluated first |
do/while | Body executes at least once |
for | Same machine shape as while, but intent is clearer |
Performance differences are usually noise. Choose based on correctness and readability.
5. foreach Under the Hood
Arrays
foreach (var x in array)
{
// …
}
- Lowered to a
forloop - Bounds checks often eliminated
- Very fast
List
- Uses a struct enumerator
- No allocation
- Still very fast
IEnumerable
⚠️ Potential performance cliff:
- Interface dispatch
- Possible allocation
- No bounds‑check elimination
Avoid IEnumerable in hot loops.
6. Bounds‑Check Elimination (BCE)
for (int i = 0; i < arr.Length; i++)
{
// …
}
Rule of thumb
- Linear access
- Single index variable
- Cached length (
int len = arr.Length;)
Weird indexing patterns can break BCE.
7. Branch Prediction: Data Beats Code
Two loops with identical code but different data:
| Data pattern | Predictability | Effect |
|---|---|---|
| 99 % predictable | Fast | Branch predictor learns the pattern |
| 50/50 random | Slower | Frequent mispredictions |
Sometimes sorting data yields bigger gains than rewriting the loop.
8. Span: Zero‑Allocation Iteration
Span<int> slice = array.AsSpan(1, 3);
foreach (ref var x in slice)
x++;
- No allocations (stack‑only)
- Cache‑friendly
- Safe
Span is one of the most important performance tools in modern .NET.
9. Vectorized Loops (SIMD Taste)
Vector<float> v1, v2;
acc += v1 * v2;
- Uses SIMD when available
- Processes multiple elements per instruction
- Great for numeric workloads
Data layout matters more than loop shape for SIMD.
10. yield return: The Hidden State Machine
IEnumerable<int> Evens()
{
yield return 2;
}
The compiler generates a state machine:
- Usually a heap allocation
- Extra indirections
Great for clarity, but avoid in ultra‑hot paths.
11. World‑Class Loop Heuristics
- ✅ Prefer contiguous memory
- ✅ Avoid allocations inside loops
- ✅ Avoid interface dispatch in hot paths
- ✅ Let the JIT eliminate bounds checks
- ✅ Measure with BenchmarkDotNet
- ✅ Optimize memory before branches
Most performance bugs are memory bugs.
12. Why This Matters for LLM‑Assisted Code
LLMs:
- Generate correct syntax
- Do not understand cache lines, branch misprediction, or GC pressure
When you (or an LLM) write loops, keep the hardware realities in mind. Write code that is:
- Memory‑friendly – contiguous, cache‑aware
- Predictable – avoid random‑access patterns that hurt branch predictors
- Allocation‑light – especially in hot paths
By doing so, you’ll get code that not only compiles but also runs efficiently—something no LLM can infer on its own.
All model is the safety net.
If you understand loops at this level, you can:
- Guide LLMs
- Review generated code intelligently
- Predict performance before profiling
- Write code that scales under real load
Final Thought
A loop is not a construct.
It is a contract between your data, the JIT, and the processor.
Once you understand that, you stop guessing — and start engineering.
Happy looping.