Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optimize performance of a Parallel.For

Tags:

c#

.net

I have replaced a for loop in my code with a Parallel.For. The performance improvement is awesome (1/3 running time). I've tried to account for shared resources using an array to gather result codes. I then process the array out side the Parallel.For. Is this the most efficient way or will blocking still occur even if no iteration can ever share the same loop-index? Would a CompareExchange perform much better?

int[] pageResults = new int[arrCounter];
Parallel.For(0, arrCounter, i =>
{
   AlertToQueueInput input = new AlertToQueueInput();
   input.Message = Messages[i];

   pageResults[i] = scCommunication.AlertToQueue(input).ReturnCode;
});

foreach (int r in pageResults)
{
    if (r != 0 && outputPC.ReturnCode == 0) outputPC.ReturnCode = r;
}
like image 800
David Avatar asked Apr 01 '26 20:04

David


2 Answers

It depends on whether you have any (valuable) side-effects in the main loop.

When the outputPC.ReturnCode is the only result, you can use PLINQ:

outputPC.ReturnCode = Messages
    .AsParallel()
    .Select(msg =>    
    {
       AlertToQueueInput input = new AlertToQueueInput();
       input.Message = msg;        
       return scCommunication.AlertToQueue(input).ReturnCode;
    })
    .FirstOrDefault(r => r != 0);

This assumes scCommunication.AlertToQueue() is thread-safe and you don't want to call it for the remaining items after the first error.

Note that FirstOrDefault() in PLinq is only efficient in Framework 4.5 and later.

like image 134
Henk Holterman Avatar answered Apr 04 '26 09:04

Henk Holterman


You could replace:

foreach (int r in pageResults)
{
    if (r != 0 && outputPC.ReturnCode == 0) outputPC.ReturnCode = r;
}

with:

foreach (int r in pageResults)
{
    if (r != 0)
    {
        outputPC.ReturnCode = r;
        break;
    }
}

This will then stop the loop on the first fail.

like image 29
David Arno Avatar answered Apr 04 '26 10:04

David Arno