I have two function generating prime numbers with the Sieves of Eratosthenes, one using simple loop, and the other using Tasks to run computations on multiple threads.
As I need to lock the list of values when using threads, I was assuming that the threaded version would not be faster than the normal version. But after some tests the normal version seems to be about 6 times worst than the threaded one.
Even stranger, when using only one Task at a time it stays 6 times faster than the normal version. What am I missing ?
Here is the code:
public static List<int> UsualPrimesGenerator(int n)
{
if (n < 0)
return new List<int>();
List<int> res = new List<int>();
for (int i = 2; i < n; i++) res.Add(i);
for (int i = 2; i * 2 <= n; i++)
{
res.RemoveAll(p => p != i && p % i == 0);
}
return res;
}
public static List<int> MagicPrimesGenerator(int n, int nbTasks)
{
if (nbTasks <= 0)
throw new ArgumentException("Nbthread must be positive");
var threads = new Task[nbTasks];
List<int> primes = new List<int>();
for (int i = 2; i <= n; i++)
primes.Add(i);
for (int i = 2; i * 2 <= primes.Count; i++)
{
if (threads[i % nbTasks] == null)
{
var i2 = i;
threads[i % nbTasks] = Task.Run(() =>
{
lock (primes)
{
primes.RemoveAll(p => p != i2 && p % i2 == 0);
}
});
}
else
{
threads[i % nbTasks].Wait();
var i2 = i;
threads[i % nbTasks] = Task.Run(() =>
{
lock (primes)
{
primes.RemoveAll(p => p != i2 && p % i2 == 0);
}
});
}
}
for (int i = 0; i < nbTasks; i++)
{
if (threads[i] != null)
threads[i].Wait();
}
return primes;
}
And the result of time tests for n = 100000:
Usual Prime Generator: 2732ms
9592 Primes found
Magic Prime Generator: 397ms
9592 Primes found