Trying to come up with strategies for finding next prime:
Algo #1 (Parallel):
private static int NextPrime(int p)
{
int nextP = 2 * p; // there is always a prime between n & 2*n !
Enumerable.Range(p + 1, p)
.AsParallel()
.ForAll(g =>
{
bool prime = true;
for (int i = 2; i <= Math.Sqrt(g); i++)
{
if (g % i == 0)
{
prime = false;
break;
}
}
if (prime)
{
if (g < nextP)
nextP = g;
return;
}
});
return nextP;
}
Algo #2 (Sequential):
private static int NextPrimeNonParallel(int p)
{
int nextP = 2 * p; // there is always a prime between n & 2*n !
foreach (var g in Enumerable.Range(p + 1, p))
{
bool prime = true;
for (int i = 2; i <= Math.Sqrt(g); i++)
{
if (g % i == 0)
{
prime = false;
break;
}
}
if (prime)
{
if (g < nextP)
nextP = g;
return nextP;
}
}
return 0;
}
Sequential is significantly faster than parallel 🙂 Why? Or is my parallel algo really well written?
Thanks!
The reason is that the parallel
ForAllwon’t terminate when it finds the first prime but will always loop though the whole range before returning, while your non parallel version will return the first value right away when its found.This will also make the parallel version buggy, since it won’t return the first found prime in the range, but actually the last found one since it overwrites nextP every time a new prime is found in the range. Note that that may not be the highest prime in the range, just the last found. Since you’re running tasks, elements may be handled out of order.
What you probably want to do instead is to use this version of Parallel.ForEach that gives you a ParallelLoopState with every iteration. If you call Break() (note: not Stop() due to out of order execution you may get a too large value then) on that object, the loop will break at earliest convenience. You will also need to make writing to nextP synchronized (it’s shared state between all threads) so that it only saves the smallest value, a’la;
That, all in all, should allow you to run in parallel with greater performance.