Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic List Performance Optimization

I am trying to optimize generic lists arithmetic operation. I have 3 lists of nullable double as defined below.

List<double?> list1 = new List<double?>();
List<double?> list2 = new List<double?>();
List<double?> listResult = new List<double?>();

int recordCount = list1.Count > list2.Count ? list2.Count : list1.Count;

for (int index = 0; index < recordCount; index++)
{
      double? result = list1[index] + list2[index];
      listResult.Add(result);
}

Is there any way to make this operation to run faster if I have huge lists?

Thanks for your input.

like image 744
Alan B Avatar asked Jan 16 '23 09:01

Alan B


1 Answers

Is there any way to make this operation to run faster if I have huge lists?

You could move your list creation for the results until after your count:

List<double?> list1 = new List<double?>();
List<double?> list2 = new List<double?>();

int recordCount = list1.Count > list2.Count ? list2.Count : list1.Count;
List<double?> listResult = new List<double?>(recordCount);

This would let you specify the exact capacity necessary for the results, and avoid reallocations within the list itself. For "huge lists" this is likely one of the slowest portions, as the memory allocations and copies as the list gets large will be the slowest operation here.

Also, if the calculation is simple, you could potentially use multiple cores:

List<double?> list1 = new List<double?>();
List<double?> list2 = new List<double?>();

int recordCount = list1.Count > list2.Count ? list2.Count : list1.Count;

var results = new double?[recordCount]; // Use an array here

Parallel.For(0, recordCount, index => 
    {
        double? result = list1[index] + list2[index];
        results[index] = result;
    });

Given that the "work" is so simple here, you probably actually would need a custom partitioner to get the most out of parallelism (see How to: Speed Up Small Loop Bodies for details):

var results = new double?[recordCount]; // Use an array here
var rangePartitioner = Partitioner.Create(0, recordCount);

Parallel.ForEach(rangePartitioner, range => 
    {
        for (int index = range.Item1; index < range.Item2; index++)
        {
            results[index] = list1[index] + list2[index];
        }
    });

If this isn't a bottleneck, however, you could use LINQ to do this as a one-liner:

var results = list1.Zip(list2, (one, two) => one + two).ToList();

However, this will be (very slightly) less efficient than handling the looping yourself, if performance is really a bottleneck.

like image 159
Reed Copsey Avatar answered Jan 22 '23 18:01

Reed Copsey