Daily Knowledge Drop
When multiple items need to be added to a List
, using the AddRange
method is generally significantly more performant than using the Add
method - however, in some scenarios it might actually be slower!
Benchmarks
In all of the below examples, an initial List of 10, 1000 and 10000 items is used as a source and transferred transferer into another destination List.
One at a time
In this benchmark, the Add
method is used to add items to a destination list, one at a time:
public void AllOneAtTime()
{
var newList = new List<int>();
foreach(var item in items)
{
newList.Add(item);
}
}
Filtered one at a time
Here, only certain items are added to the destination list (this divisible by 2). A check is performed, and only if it passes is the specific item added to the list:
public void FilteredOneAtTime()
{
var newList = new List<int>();
foreach (var item in items)
{
// only if divisible by 2
if (item % 2 == 0)
{
newList.Add(item);
}
}
}
Add range
In this benchmark, the entire source list is copied to the destination list using the AddRange
method:
public void AllOnce()
{
var newList = new List<int>();
newList.AddRange(items);
}
Filtered add range
In the final benchmark, the entire source list is filtered using LINQ, and then AddRange
is used:
public void FilteredOnce()
{
var newList = new List<int>();
newList.AddRange(items.Where(i => i % 2 == 0).ToList());
}
Performance
The full results are below, but in summary:
AddRange
is 2-3 times faster than usingAdd
multiple times (depending on the list size)- When required to filter the list, its quicker to iterate through each item, perform the check and use
Add
. This is in comparison to using LINQ to filter and thenAddRange
(the bottleneck here is LINQ, not the AddRange call)
10 items
Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
---|---|---|---|---|---|---|---|---|
AllOneAtTime | 59.21 ns | 0.873 ns | 0.817 ns | 1.00 | 0.00 | 0.0343 | 216 B | 1.00 |
FilteredOneAtTime | 40.12 ns | 0.738 ns | 0.690 ns | 0.68 | 0.01 | 0.0204 | 128 B | 0.59 |
AllOnce | 23.10 ns | 0.458 ns | 0.450 ns | 0.39 | 0.01 | 0.0153 | 96 B | 0.44 |
FilteredOnce | 97.60 ns | 1.395 ns | 1.305 ns | 1.65 | 0.04 | 0.0446 | 280 B | 1.30 |
1000 items
Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Allocated | Alloc Ratio |
---|---|---|---|---|---|---|---|---|---|
AllOneAtTime | 2,155.3 ns | 40.86 ns | 43.72 ns | 1.00 | 0.00 | 1.3390 | 0.0229 | 8.23 KB | 1.00 |
FilteredOneAtTime | 1,554.8 ns | 30.15 ns | 38.13 ns | 0.72 | 0.02 | 0.6847 | 0.0057 | 4.2 KB | 0.51 |
AllOnce | 216.5 ns | 3.27 ns | 3.06 ns | 0.10 | 0.00 | 0.6464 | 0.0098 | 3.96 KB | 0.48 |
FilteredOnce | 2,870.1 ns | 36.82 ns | 34.44 ns | 1.33 | 0.03 | 1.0223 | 0.0153 | 6.28 KB | 0.76 |
10000 items
Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Allocated | Alloc Ratio |
---|---|---|---|---|---|---|---|---|---|
AllOneAtTime | 21.498 us | 0.4191 us | 0.4659 us | 1.00 | 0.00 | 20.8130 | 4.1504 | 128.32 KB | 1.00 |
FilteredOneAtTime | 15.165 us | 0.1404 us | 0.1172 us | 0.71 | 0.02 | 10.4675 | 1.2817 | 64.3 KB | 0.50 |
AllOnce | 2.127 us | 0.0408 us | 0.0382 us | 0.10 | 0.00 | 6.3667 | 0.7935 | 39.12 KB | 0.30 |
FilteredOnce | 28.335 us | 0.3079 us | 0.2729 us | 1.32 | 0.03 | 13.6414 | 2.2583 | 83.95 KB | 0.65 |
Notes
Generally, AddRange
is much quicker than multiple iterations of Add
- however, if using AddRange
in conjunction with a slower operation (such as LINQ's where), then it doesn't really matter which is used, and to improve performance the bottleneck (LINQ) should be optimized.
References
Daily Drop 200: 11-11-2022
At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.
The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.