Reputation: 49
I have an array of 921600 numbers between 0 and 255.
I need to check each number whether it's above a threshold or not.
Is it possible to check the first- and second half of the array at the same time, to cut down on run time?
What I mean is, is it possible to run the following two for loops in parallel?
for(int i = 0; i < 921600 / 2; i++)
{
if(arr[i] > 240) counter++;
}
for(int j = 921600 / 2; j < 921600; j++)
{
if(arr[j] > 240) counter++;
}
Thank you in advance!
Upvotes: 4
Views: 4771
Reputation: 11
while googling for parallel concepts, came across your query. Might be the below little trick might help you
int n=921600/2;
for(int i=0; i<n; i++)
{
if(arr[i]>240) counter ++;
if(arr[n + i] > 240) counter ++;
}
Upvotes: 1
Reputation: 101
What you are asking is strictly possible as per below.
int counter = 0;
var tasks = new List<Task>();
var arr = Enumerable.Range(0, 921600).ToArray();
tasks.Add(Task.Factory.StartNew(() =>
{
for (int i = 0; i < 921600 / 2; i++)
{
if (arr[i] > 240) counter++;
}
}));
tasks.Add(Task.Factory.StartNew(() =>
{
for (int j = 921600 / 2; j < 921600; j++)
{
if (arr[j] > 240) counter++;
}
}));
Task.WaitAll(tasks.ToArray());
Do not use this code! You will encounter a race condition with incrementing the integer where one thread's increment is lost due to a Read, Read, Write, Write situation. Running this in LinqPad, I ended up with counter being anything between 600000 and 800000. Obviously that range is nowhere near the actual value.
The solution to this race condition is to introduce a lock that means that only one thread can touch the variable at any one time. This negates the ability for the assignment to be multithreaded but allows us to get the correct answer. (This takes 0.042s on my machine for reference)
int counter = 0;
var tasks = new List<Task>();
var arr = Enumerable.Range(0, 921600).ToArray();
var locker = new Object();
tasks.Add(Task.Factory.StartNew(() =>
{
for (int i = 0; i < 921600 / 2; i++)
{
if (arr[i] > 240)
lock (locker)
counter++;
}
}));
tasks.Add(Task.Factory.StartNew(() =>
{
for (int j = 921600 / 2; j < 921600; j++)
{
if (arr[j] > 240)
lock (locker)
counter++;
}
}));
Task.WaitAll(tasks.ToArray());
The solution is indeed to use Parallel Linq as Dmitry has suggested:
Enumerable.Range(0, 921600).AsParallel().Count(x=>x>240);
This takes 0.031s which is quicker than our locking code and still returns the correct answer but removing the AsParallel call makes it run in 0.024s. Running a piece of code in parallel introduces a overhead to manage the threads. Sometimes the performance improvement outweighs this but a surprisingly large amount of the time it doesn't.
The moral of the story is to always run some metrics/timings of your expected data against your implementation of any code to check whether there is actually a performance benefit.
Upvotes: 2
Reputation: 186678
I suggest using Parallel Linq (PLinq) for this
int[] source = ...
int count = source
.AsParallel() // comment this out if you want sequential version
.Count(item => item > 240);
Upvotes: 9