Identify and compare the performance of loops and data structures in dotnet.
Read All Elements
Method
N
Mean
Error
StdDev
Gen 0
Gen 1
Gen 2
Allocated
Array
10
8.462 ns
0.1004 ns
0.0939 ns
-
-
-
-
List
10
37.746 ns
0.5316 ns
0.4972 ns
-
-
-
-
Dictionary
10
45.030 ns
0.5924 ns
0.5541 ns
-
-
-
-
Enumerable
10
92.544 ns
1.8599 ns
1.8266 ns
0.0030
-
-
32 B
Array
100
88.140 ns
0.2264 ns
0.2118 ns
-
-
-
-
List
100
325.107 ns
0.4612 ns
0.4088 ns
-
-
-
-
Dictionary
100
398.824 ns
5.3828 ns
4.7717 ns
-
-
-
-
Enumerable
100
791.363 ns
0.7508 ns
0.6269 ns
0.0029
-
-
32 B
Array
1000
799.742 ns
1.1529 ns
0.9627 ns
-
-
-
-
List
1000
3,129.860 ns
30.2348 ns
28.2816 ns
-
-
-
-
Dictionary
1000
3,802.089 ns
6.8087 ns
5.6856 ns
-
-
-
-
Enumerable
1000
7,557.364 ns
14.4488 ns
11.2807 ns
-
-
-
32 B
Array
10000
7,958.463 ns
13.5116 ns
11.9777 ns
-
-
-
-
List
10000
31,219.201 ns
333.8981 ns
295.9920 ns
-
-
-
-
Dictionary
10000
37,876.099 ns
114.4200 ns
107.0285 ns
-
-
-
-
Enumerable
10000
75,158.884 ns
70.4157 ns
62.4217 ns
-
-
-
32 B
Array
100000
80,106.295 ns
418.6813 ns
391.6347 ns
-
-
-
-
List
100000
310,237.252 ns
315.2137 ns
263.2177 ns
-
-
-
1 B
Dictionary
100000
377,772.063 ns
374.2141 ns
331.7310 ns
-
-
-
1 B
Enumerable
100000
750,889.481 ns
1,095.9584 ns
971.5385 ns
-
-
-
33 B
Array
1000000
808,059.982 ns
4,516.5571 ns
4,003.8103 ns
-
-
-
1 B
List
1000000
3,108,008.650 ns
2,550.8694 ns
2,261.2793 ns
-
-
-
5 B
Dictionary
1000000
3,858,242.020 ns
11,047.8311 ns
9,793.6145 ns
-
-
-
5 B
Enumerable
1000000
7,547,736.458 ns
54,061.0389 ns
50,568.7293 ns
-
-
-
42 B
Array's are the fastest data structure to read all elements from.
Lists are 6.5 times slower when N = 10 and 4.15 times slower when N = 1M.
Dictionary's are only ~20% slower than lists. A relatively minor performance hit.
Using the IEnumerable interface on top of an Array is 14 times slower when N = 10 and 8.3 times slower when N = 1M.
Read a Random Element
Method
N
Mean
Error
StdDev
Gen 0
Gen 1
Gen 2
Allocated
Array
10
18.16 ns
0.010 ns
0.008 ns
-
-
-
-
List
10
18.74 ns
0.016 ns
0.014 ns
-
-
-
-
Dictionary
10
32.67 ns
0.177 ns
0.148 ns
-
-
-
-
Enumerable
10
62.17 ns
0.026 ns
0.020 ns
-
-
-
-
Array
100
18.17 ns
0.019 ns
0.018 ns
-
-
-
-
List
100
18.86 ns
0.214 ns
0.200 ns
-
-
-
-
Dictionary
100
31.64 ns
0.546 ns
0.510 ns
-
-
-
-
Enumerable
100
61.26 ns
0.315 ns
0.279 ns
-
-
-
-
Array
1000
18.16 ns
0.010 ns
0.009 ns
-
-
-
-
List
1000
18.86 ns
0.195 ns
0.173 ns
-
-
-
-
Dictionary
1000
31.34 ns
0.018 ns
0.017 ns
-
-
-
-
Enumerable
1000
61.25 ns
0.240 ns
0.213 ns
-
-
-
-
Array
10000
18.53 ns
0.010 ns
0.008 ns
-
-
-
-
List
10000
19.18 ns
0.426 ns
0.418 ns
-
-
-
-
Dictionary
10000
32.61 ns
0.018 ns
0.015 ns
-
-
-
-
Enumerable
10000
61.20 ns
0.225 ns
0.188 ns
-
-
-
-
Array
100000
19.06 ns
0.007 ns
0.006 ns
-
-
-
-
List
100000
20.85 ns
0.412 ns
0.386 ns
-
-
-
-
Dictionary
100000
42.78 ns
0.169 ns
0.150 ns
-
-
-
-
Enumerable
100000
61.56 ns
0.298 ns
0.249 ns
-
-
-
-
Array
1000000
20.51 ns
0.394 ns
0.369 ns
-
-
-
-
List
1000000
20.01 ns
0.285 ns
0.267 ns
-
-
-
-
Dictionary
1000000
86.46 ns
1.564 ns
1.463 ns
-
-
-
-
Enumerable
1000000
66.15 ns
1.372 ns
1.409 ns
-
-
-
-
Read the First Element
Method
N
Mean
Error
StdDev
Gen 0
Gen 1
Gen 2
Allocated
Array
1000000
0.4420 ns
0.0090 ns
0.0080 ns
-
-
-
-
List
1000000
0.4546 ns
0.0160 ns
0.0142 ns
-
-
-
-
Enumerable
1000000
42.8946 ns
0.0515 ns
0.0457 ns
-
-
-
-
Read the Last Element
Method
N
Mean
Error
StdDev
Median
Gen 0
Gen 1
Gen 2
Allocated
Array
1000000
0.0031 ns
0.0052 ns
0.0049 ns
0.0000 ns
-
-
-
-
List
1000000
0.5693 ns
0.0017 ns
0.0015 ns
0.5689 ns
-
-
-
-
Enumerable
1000000
43.1204 ns
0.2835 ns
0.2652 ns
43.0264 ns
-
-
-
-
Read a Specific Element
Method
N
Mean
Error
StdDev
Gen 0
Gen 1
Gen 2
Allocated
Array
10
6.654 ns
0.0964 ns
0.0902 ns
-
-
-
-
List
10
12.528 ns
0.0302 ns
0.0268 ns
-
-
-
-
Dictionary
10
12.596 ns
0.1338 ns
0.1252 ns
-
-
-
-
Enumerable
10
104.985 ns
2.1010 ns
3.0132 ns
0.0106
-
-
112 B
Array
100
46.228 ns
0.2222 ns
0.2079 ns
-
-
-
-
List
100
109.426 ns
0.6678 ns
0.5920 ns
-
-
-
-
Dictionary
100
12.295 ns
0.0223 ns
0.0174 ns
-
-
-
-
Enumerable
100
250.941 ns
4.3398 ns
4.0594 ns
0.0105
-
-
112 B
Array
1000
439.344 ns
4.9141 ns
4.5967 ns
-
-
-
-
List
1000
942.661 ns
0.5443 ns
0.5091 ns
-
-
-
-
Dictionary
1000
12.528 ns
0.1591 ns
0.1410 ns
-
-
-
-
Enumerable
1000
1,572.533 ns
3.3320 ns
3.1168 ns
0.0095
-
-
112 B
Array
10000
4,207.046 ns
2.7252 ns
2.2756 ns
-
-
-
-
List
10000
9,289.749 ns
8.6985 ns
7.2637 ns
-
-
-
-
Dictionary
10000
12.837 ns
0.1375 ns
0.1286 ns
-
-
-
-
Enumerable
10000
15,118.351 ns
283.6053 ns
278.5383 ns
-
-
-
112 B
Array
100000
42,533.988 ns
653.0281 ns
610.8429 ns
-
-
-
-
List
100000
93,499.006 ns
68.5882 ns
57.2743 ns
-
-
-
-
Dictionary
100000
12.466 ns
0.2935 ns
0.2746 ns
-
-
-
-
Enumerable
100000
149,119.863 ns
2,081.4885 ns
1,947.0257 ns
-
-
-
114 B
Array
1000000
426,127.438 ns
993.7234 ns
880.9099 ns
-
-
-
5 B
List
1000000
949,036.021 ns
12,406.9680 ns
10,998.4540 ns
-
-
-
1 B
Dictionary
1000000
12.805 ns
0.7688 ns
0.7551 ns
-
-
-
-
Enumerable
1000000
1,471,627.427 ns
2,970.2328 ns
2,633.0340 ns
-
-
-
115 B
Write All Elements from an Array
Method
N
Mean
Error
StdDev
Gen 0
Gen 1
Gen 2
Allocated
Array
10
20.19 ns
0.173 ns
0.162 ns
0.0061
-
-
64 B
ListAdd
10
125.15 ns
0.325 ns
0.288 ns
0.0205
-
-
216 B
ListAddRange
10
72.11 ns
0.125 ns
0.104 ns
0.0092
-
-
96 B
DictionaryAdd
10
406.24 ns
0.887 ns
0.787 ns
0.0734
-
-
768 B
DictionaryTryAdd
10
404.84 ns
2.164 ns
2.024 ns
0.0734
-
-
768 B
Array
100
130.42 ns
2.101 ns
1.863 ns
0.0405
-
-
424 B
ListAdd
100
576.42 ns
2.392 ns
2.237 ns
0.1125
-
-
1184 B
ListAddRange
100
123.20 ns
0.720 ns
0.673 ns
0.0434
-
-
456 B
DictionaryAdd
100
3,590.04 ns
22.021 ns
20.599 ns
0.7057
0.0114
-
7384 B
DictionaryTryAdd
100
3,614.08 ns
4.907 ns
4.350 ns
0.7057
0.0114
-
7384 B
Array
1000
1,150.38 ns
11.193 ns
10.470 ns
0.3834
-
-
4024 B
ListAdd
1000
3,858.67 ns
12.355 ns
11.557 ns
0.8011
0.0153
-
8424 B
ListAddRange
1000
537.78 ns
12.548 ns
11.737 ns
0.3872
0.0057
-
4056 B
DictionaryAdd
1000
33,913.77 ns
76.949 ns
71.978 ns
6.9580
1.0376
-
73160 B
DictionaryTryAdd
1000
35,224.03 ns
58.757 ns
54.962 ns
6.9580
1.0986
-
73160 B
Array
10000
10,776.14 ns
48.028 ns
44.926 ns
3.8147
-
-
40024 B
ListAdd
10000
43,018.69 ns
442.264 ns
392.055 ns
12.4512
2.4414
-
131400 B
ListAddRange
10000
5,747.48 ns
38.101 ns
35.640 ns
3.8147
0.4730
-
40056 B
DictionaryAdd
10000
463,246.09 ns
582.210 ns
486.172 ns
124.5117
124.5117
124.5117
673057 B
DictionaryTryAdd
10000
481,237.39 ns
6,601.390 ns
6,174.945 ns
124.5117
124.5117
124.5117
673061 B
Array
100000
256,847.50 ns
409.768 ns
319.920 ns
124.5117
124.5117
124.5117
400025 B
ListAdd
100000
660,658.81 ns
4,265.502 ns
3,989.953 ns
285.1563
285.1563
285.1563
1048981 B
ListAddRange
100000
241,667.06 ns
389.111 ns
363.974 ns
124.7559
124.7559
124.7559
400056 B
DictionaryAdd
100000
3,554,851.17 ns
8,874.704 ns
8,301.404 ns
1023.4375
1000.0000
1000.0000
6037627 B
DictionaryTryAdd
100000
3,711,831.22 ns
5,310.246 ns
4,434.296 ns
1023.4375
1000.0000
1000.0000
6037630 B
Array
1000000
1,533,038.94 ns
30,614.551 ns
52,808.596 ns
218.7500
218.7500
218.7500
4000019 B
ListAdd
1000000
7,411,313.04 ns
30,983.108 ns
25,872.298 ns
500.0000
492.1875
492.1875
8389078 B
ListAddRange
1000000
1,103,381.51 ns
17,380.970 ns
14,513.897 ns
220.7031
220.7031
220.7031
4000060 B
DictionaryAdd
1000000
34,201,491.11 ns
50,923.897 ns
47,634.244 ns
1000.0000
1000.0000
1000.0000
53888539 B
DictionaryTryAdd
1000000
35,962,784.18 ns
52,817.353 ns
46,821.208 ns
1071.4286
1071.4286
1071.4286
53888537 B
Copy Dictionary Values to a Stack
Method
N
Mean
Error
StdDev
Gen 0
Gen 1
Gen 2
Allocated
ForEach
10
225.6 ns
4.35 ns
4.28 ns
0.0205
-
-
216 B
LinqSelect
10
460.3 ns
6.10 ns
5.40 ns
0.0296
-
-
312 B
LinqSelectIntermediate
10
489.9 ns
8.02 ns
7.11 ns
0.0401
-
-
424 B
ForEach
100
1,264.8 ns
24.48 ns
32.68 ns
0.1125
-
-
1184 B
LinqSelect
100
2,818.9 ns
10.88 ns
9.09 ns
0.1221
-
-
1280 B
LinqSelectIntermediate
100
2,792.3 ns
44.31 ns
41.45 ns
0.1984
-
-
2112 B
ForEach
1000
9,700.1 ns
148.59 ns
124.08 ns
0.7935
0.0153
-
8424 B
LinqSelect
1000
27,447.0 ns
148.41 ns
123.93 ns
0.7935
-
-
8520 B
LinqSelectIntermediate
1000
24,636.1 ns
385.38 ns
321.81 ns
1.5564
0.0610
-
16552 B
ForEach
10000
108,557.5 ns
2,143.56 ns
3,273.44 ns
12.4512
2.4414
-
131400 B
LinqSelect
10000
277,094.5 ns
4,523.74 ns
4,231.51 ns
12.2070
1.9531
-
131496 B
LinqSelectIntermediate
10000
244,094.5 ns
3,105.54 ns
2,904.92 ns
20.0195
6.3477
-
211528 B
ForEach
100000
1,071,301.5 ns
14,155.48 ns
13,241.04 ns
158.2031
146.4844
146.4844
1049727 B
LinqSelect
100000
2,749,630.3 ns
19,226.19 ns
16,054.74 ns
183.5938
171.8750
171.8750
1049087 B
LinqSelectIntermediate
100000
2,451,562.1 ns
12,058.18 ns
10,689.26 ns
250.0000
238.2813
238.2813
1849206 B
ForEach
1000000
13,343,144.1 ns
80,963.98 ns
71,772.46 ns
62.5000
62.5000
62.5000
8389326 B
LinqSelect
1000000
29,841,091.7 ns
551,582.72 ns
515,950.82 ns
62.5000
62.5000
62.5000
8389184 B
LinqSelectIntermediate
1000000
29,366,898.8 ns
466,779.27 ns
436,625.62 ns
125.0000
125.0000
125.0000
16389701 B
Using a Foreach loop is 2.14 times faster when N = 10 and 2 times as faster when N = 1M.
Using an intermediate varible in a Linq Select loop has no performance impact when N = 10 and a 9% performance hit when N = 1M.
Loop Over All Elements After using To Array
Method
N
Mean
Error
StdDev
Gen 0
Gen 1
Gen 2
Allocated
ListForeach
10
59.51 ns
1.242 ns
1.479 ns
-
-
-
-
ListToArrayForeach
10
44.50 ns
0.421 ns
0.373 ns
0.0099
-
-
104 B
DictionaryForeach
10
93.68 ns
1.289 ns
1.206 ns
-
-
-
-
DictionaryValuesToArrayForeach
10
105.72 ns
0.722 ns
0.603 ns
0.0099
-
-
104 B
DictionaryToArrayForeach
10
130.14 ns
0.538 ns
0.503 ns
0.0174
-
-
184 B
ListForeach
100
531.67 ns
0.470 ns
0.439 ns
-
-
-
-
ListToArrayForeach
100
197.21 ns
2.681 ns
2.508 ns
0.0787
-
-
824 B
DictionaryForeach
100
712.14 ns
2.195 ns
1.946 ns
-
-
-
-
DictionaryValuesToArrayForeach
100
631.58 ns
3.862 ns
3.225 ns
0.0782
-
-
824 B
DictionaryToArrayForeach
100
842.79 ns
5.757 ns
5.104 ns
0.1545
-
-
1624 B
ListForeach
1000
5,499.52 ns
27.582 ns
24.451 ns
-
-
-
-
ListToArrayForeach
1000
2,384.59 ns
14.385 ns
12.752 ns
0.7668
-
-
8024 B
DictionaryForeach
1000
6,728.26 ns
63.305 ns
59.215 ns
-
-
-
-
DictionaryValuesToArrayForeach
1000
6,207.76 ns
31.319 ns
27.764 ns
0.7629
-
-
8024 B
DictionaryToArrayForeach
1000
8,192.87 ns
36.321 ns
33.975 ns
1.5259
-
-
16024 B
ListForeach
10000
51,189.58 ns
152.732 ns
127.538 ns
-
-
-
-
ListToArrayForeach
10000
31,273.19 ns
163.439 ns
152.881 ns
7.6294
-
-
80025 B
DictionaryForeach
10000
63,149.54 ns
26.116 ns
24.428 ns
-
-
-
-
DictionaryValuesToArrayForeach
10000
68,081.66 ns
173.836 ns
162.606 ns
7.5684
-
-
80025 B
DictionaryToArrayForeach
10000
163,897.22 ns
891.283 ns
833.707 ns
49.8047
49.8047
49.8047
160025 B
ListForeach
100000
515,107.94 ns
671.571 ns
628.188 ns
-
-
-
-
ListToArrayForeach
100000
643,289.06 ns
3,328.741 ns
3,113.706 ns
25.3906
25.3906
25.3906
800026 B
DictionaryForeach
100000
634,093.07 ns
1,589.341 ns
1,408.910 ns
-
-
-
7 B
DictionaryValuesToArrayForeach
100000
788,784.90 ns
10,006.459 ns
9,360.048 ns
67.3828
67.3828
67.3828
800018 B
DictionaryToArrayForeach
100000
1,001,216.33 ns
15,421.245 ns
12,877.438 ns
74.2188
74.2188
74.2188
1600019 B
ListForeach
1000000
6,282,542.40 ns
13,524.965 ns
12,651.260 ns
-
-
-
-
ListToArrayForeach
1000000
8,787,632.14 ns
62,242.102 ns
55,176.002 ns
31.2500
31.2500
31.2500
8000022 B
DictionaryForeach
1000000
7,037,605.08 ns
26,557.130 ns
24,841.556 ns
-
-
-
-
DictionaryValuesToArrayForeach
1000000
13,795,614.29 ns
116,910.615 ns
103,638.215 ns
62.5000
62.5000
62.5000
8000022 B
DictionaryToArrayForeach
1000000
16,650,591.04 ns
50,160.654 ns
46,920.307 ns
62.5000
62.5000
62.5000
16000022 B
When N < 100,000 using the ToArray method on a List and then looping over its result is faster than simply looping over the List.
Theory: The degrading performance of the List.ToArray version could be because it uses Array.CopyTo under the hood which will use twice as much memory as simply looping over the List. The larger object sizes could be forcing these data structures on to the Large Object Heap and inducing more intervention from the Garbage Collector. This could be confirmed by profiling the memory consumption and garbage collections of these benchmarks.
It's always faster to just foreach over a Dictioinary than it is to extract its elements and then loop over them.