我有一个简单的代码,可以找到1到100000之间的所有素数.
问题是,这不准确.有9592个素数在1到100000之间,但我得到的值从9588到9592.代码是:
Listresult = new List (); Stopwatch watch = Stopwatch.StartNew(); List tasks = new List (); 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作为结果;
为什么会这样发生,我该如何解决?
您正在List
从多个线程添加.没有同步就不支持.如果添加一些锁定,你可能会发现它有效......但是使用并行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作为输入.