我有一个简单的代码,可以找到1到100000之间的所有素数。
问题是,它不准确。在1到100000之间有9592个素数,但我得到的值在9588到9592之间。 代码是:
List<bool> result = new List<bool>();
Stopwatch watch = Stopwatch.StartNew();
List<Task> tasks = new List<Task>();
for (ulong i = 1; i < 100000; i++)
{
tasks.Add(Task.Factory.StartNew(number =>
{
var y = (ulong)number;
if (y == 1) return false;
if (y == 2) return true;
for (ulong j = 3; j < y; j++)
{
if (y % j == 0)
return false;
}
return true;
}, i).ContinueWith(x => result.Add(x.Result))
);
}
Task.WaitAll(tasks.ToArray());
watch.Stop();
Console.WriteLine("done in {0}, primes {1}", watch.ElapsedMilliseconds, result.Count(x => x));
如果我运行此代码10次,这就是我得到的:
done in 2764, primes 9588
done in 2528, primes 9589
done in 2433, primes 9591
done in 2502, primes 9589
done in 2400, primes 9591
done in 2401, primes 9589
done in 2417, primes 9591
done in 2440, primes 9590
done in 2423, primes 9592
done in 2397, primes 9590
每次迭代我都希望它返回9592作为结果;
为什么会这样发生,我该如何解决?
答案 0 :(得分:7)
您正在从多个主题添加List<T>
。没有同步就不支持。如果添加一些锁定,你可能会发现它有效......但是使用并行LINQ会更简单。像这样:
using System;
using System.Linq;
class Program
{
static void Main(string[] args)
{
var primes = Enumerable.Range(1, 100000)
.AsParallel()
.Where(IsPrime)
.ToList();
Console.WriteLine(primes.Count);
}
static bool IsPrime(int number)
{
if (number == 1) return false;
// TODO: Only go up to Math.Sqrt(number)
for (int j = 2; j < number; j++)
{
if (number % j == 0)
{
return false;
}
}
return true;
}
}
请注意,我已修复了代码中的错误 - 您的原始代码会使4为素数,因为您在3而不是2处开始内循环。不需要特殊情况2作为输入,或者
答案 1 :(得分:2)
您可以使用parallel LINQ (PLINQ)
代替@Jon Skeet说。像这样:
private int DoParallel(int first,int max)
{
var numbers = Enumerable.Range(first, max - 9);
var parallelQuery = numbers.AsParallel()
.Where(n => Enumerable.Range(2, (int)Math.Sqrt(n))
.All(i => n % i != 0));
return parallelQuery.Count();
}