Last active
June 8, 2026 15:27
-
-
Save udlose/fe2a25d05b7f2eadee25fb70d9946df7 to your computer and use it in GitHub Desktop.
.NET Benchmark and Results for comparing iteration using foreach vs for over ArrayList containing Reference Type
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections; | |
| using System.Runtime.CompilerServices; | |
| using BenchmarkDotNet.Attributes; | |
| using BenchmarkDotNet.Columns; | |
| using BenchmarkDotNet.Configs; | |
| using BenchmarkDotNet.Engines; | |
| using BenchmarkDotNet.Running; | |
| [MemoryDiagnoser] | |
| [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] | |
| [CategoriesColumn] | |
| public class IterationBenchmarks | |
| { | |
| [Params(1_000, 10_000, 50_000)] | |
| public int Count; | |
| private ArrayList _arrayList = null; | |
| private Consumer _consumer = null; | |
| [GlobalSetup] | |
| public void GlobalSetup() | |
| { | |
| _arrayList = new ArrayList(Count); | |
| for (int i = 0; i < Count; i++) | |
| { | |
| IPerson p = new Person(i, $"Dwight Schrute{i}"); | |
| _arrayList.Add(p); // boxed | |
| } | |
| // Create once and reuse, so you don't benchmark Consumer construction | |
| _consumer = new Consumer(); | |
| } | |
| [Benchmark(Baseline = true, Description = "ArrayList<Person> foreach")] | |
| public void ArrayList_Foreach() | |
| { | |
| foreach (object item in _arrayList) | |
| { | |
| IPerson p = (Person)item; // unbox | |
| _consumer.Consume(p); | |
| } | |
| } | |
| [Benchmark(Description = "ArrayList<Person> for")] | |
| public void ArrayList_For() | |
| { | |
| for (int i = 0; i < _arrayList.Count; i++) | |
| { | |
| IPerson value = (Person)_arrayList[i]; // indexer returns object -> unbox | |
| _consumer.Consume(value); | |
| } | |
| } | |
| [Benchmark(Description = "ArrayList<Person> for (with hoisted Count property)")] | |
| public void ArrayList_For_Hoisted_Count() | |
| { | |
| int count = _arrayList.Count; // hoist Count to avoid virtual dispatch | |
| for (int i = 0; i < count; i++) | |
| { | |
| IPerson value = (Person)_arrayList[i]; // indexer returns object -> unbox | |
| _consumer.Consume(value); | |
| } | |
| } | |
| } | |
| public static class Program | |
| { | |
| public static void Main(string[] args) | |
| { | |
| IConfig config = DefaultConfig.Instance | |
| .WithOption(ConfigOptions.DisableOptimizationsValidator, true) | |
| .AddColumn(RankColumn.Arabic) | |
| .AddColumn(StatisticColumn.OperationsPerSecond) | |
| .WithSummaryStyle( | |
| SummaryStyle.Default | |
| .WithCultureInfo(System.Globalization.CultureInfo.GetCultureInfo("en-US")) | |
| .WithRatioStyle(RatioStyle.Trend)); | |
| BenchmarkRunner.Run<IterationBenchmarks>(config); | |
| } | |
| } | |
| public interface IPerson | |
| { | |
| int Compute(); | |
| } | |
| public class Person : IPerson | |
| { | |
| public readonly int Id; | |
| public readonly string Name; | |
| public Person(int id, string name) | |
| { | |
| Id = id; | |
| Name = name; | |
| } | |
| public int Compute() | |
| { | |
| // Cheap deterministic work; no allocations; good for net48 + net8. | |
| Random rand = new Random(); | |
| int x = rand.Next() ^ (Id * 397); | |
| x = (x << 5) | (int)((uint)x >> 27); | |
| x = x * 31 + Id; | |
| return x; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Run time: 00:03:06 (186.01 sec), executed benchmarks: 9 | |
| // * Summary * | |
| BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.8390/25H2/2025Update/HudsonValley2) | |
| 12th Gen Intel Core i7-12800H 2.40GHz, 1 CPU, 20 logical and 14 physical cores | |
| .NET SDK 10.0.300 | |
| [Host] : .NET 10.0.8 (10.0.8, 10.0.826.23019), X64 RyuJIT x86-64-v3 | |
| | Method | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio | | |
| |------------------------------------------------------ |------ |-----------:|----------:|----------:|-------------:|--------:|-------:|----------:|------------:| | |
| | 'ArrayList<Person> foreach' | 1000 | 2.467 μs | 0.0277 μs | 0.0259 μs | baseline | | 0.0038 | 48 B | | | |
| | 'ArrayList<Person> for' | 1000 | 1.948 μs | 0.0258 μs | 0.0242 μs | 1.27x faster | 0.02x | - | - | NA | | |
| | 'ArrayList<Person> for (with hoisted Count property)' | 1000 | 1.808 μs | 0.0187 μs | 0.0175 μs | 1.36x faster | 0.02x | - | - | NA | | |
| | | | | | | | | | | | | |
| | 'ArrayList<Person> foreach' | 10000 | 25.160 μs | 0.4454 μs | 0.4166 μs | baseline | | - | 48 B | | | |
| | 'ArrayList<Person> for' | 10000 | 19.865 μs | 0.1721 μs | 0.1610 μs | 1.27x faster | 0.02x | - | - | NA | | |
| | 'ArrayList<Person> for (with hoisted Count property)' | 10000 | 18.456 μs | 0.2452 μs | 0.2293 μs | 1.36x faster | 0.03x | - | - | NA | | |
| | | | | | | | | | | | | |
| | 'ArrayList<Person> foreach' | 50000 | 122.440 μs | 0.7770 μs | 0.6888 μs | baseline | | - | 49 B | | | |
| | 'ArrayList<Person> for' | 50000 | 99.981 μs | 1.6674 μs | 1.5597 μs | 1.22x faster | 0.02x | - | 1 B | 49.00x less | | |
| | 'ArrayList<Person> for (with hoisted Count property)' | 50000 | 92.652 μs | 1.2633 μs | 1.1817 μs | 1.32x faster | 0.02x | - | - | NA | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.8390/25H2/2025Update/HudsonValley2) | |
| 12th Gen Intel Core i7-12800H 2.40GHz, 1 CPU, 20 logical and 14 physical cores | |
| [Host] : .NET Framework 4.8.1 (4.8.9325.0), X64 RyuJIT VectorSize=256 | |
| DefaultJob : .NET Framework 4.8.1 (4.8.9325.0), X64 RyuJIT VectorSize=256 | |
| | Method | Count | Mean | Error | StdDev | Op/s | Ratio | RatioSD | Rank | Allocated | Alloc Ratio | | |
| |------------------------------------------------------ |------ |-----------:|----------:|----------:|----------:|-------------:|--------:|-----:|----------:|------------:| | |
| | 'ArrayList<Person> foreach' | 1000 | 7.946 μs | 0.1309 μs | 0.1455 μs | 125,857.0 | baseline | | 3 | 48 B | | | |
| | 'ArrayList<Person> for' | 1000 | 3.131 μs | 0.0409 μs | 0.0383 μs | 319,378.7 | 2.54x faster | 0.05x | 2 | - | NA | | |
| | 'ArrayList<Person> for (with hoisted Count property)' | 1000 | 2.246 μs | 0.0356 μs | 0.0297 μs | 445,322.5 | 3.54x faster | 0.08x | 1 | - | NA | | |
| | | | | | | | | | | | | | |
| | 'ArrayList<Person> foreach' | 10000 | 79.549 μs | 1.4641 μs | 1.3695 μs | 12,570.8 | baseline | | 3 | 48 B | | | |
| | 'ArrayList<Person> for' | 10000 | 32.255 μs | 0.6338 μs | 0.8461 μs | 31,003.3 | 2.47x faster | 0.08x | 2 | - | NA | | |
| | 'ArrayList<Person> for (with hoisted Count property)' | 10000 | 23.029 μs | 0.4540 μs | 0.6061 μs | 43,424.4 | 3.46x faster | 0.11x | 1 | - | NA | | |
| | | | | | | | | | | | | | |
| | 'ArrayList<Person> foreach' | 50000 | 386.441 μs | 5.1569 μs | 4.8238 μs | 2,587.7 | baseline | | 3 | 48 B | | | |
| | 'ArrayList<Person> for' | 50000 | 162.241 μs | 2.8141 μs | 2.6323 μs | 6,163.7 | 2.38x faster | 0.05x | 2 | - | NA | | |
| | 'ArrayList<Person> for (with hoisted Count property)' | 50000 | 116.088 μs | 0.7555 μs | 0.7067 μs | 8,614.2 | 3.33x faster | 0.04x | 1 | - | NA | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment