并行函数在 C# 中返回不同的结果
本文关键字:结果 返回 函数 并行 | 更新日期: 2023-09-27 18:35:15
我的Windows表单C#应用程序中有这些代码:
private void button7_Click(object sender, EventArgs e)
{
ThreadStart starter = delegate { thread_func(2, 1000000); };
thread1_thread = new Thread(starter);
starter = delegate { thread_func(1000000, 2000000); };
thread2_thread = new Thread(starter);
starter = delegate { thread_func(2000000, 3000000); };
thread3_thread = new Thread(starter);
starter = delegate { thread_func(3000000, 4000000); };
thread4_thread = new Thread(starter);
thread1_thread.Start();
thread2_thread.Start();
thread3_thread.Start();
thread4_thread.Start();
}
void thread_func(decimal input1,decimal input2)
{
for (; input1 < input2; input1++)
{
threadNumbers_list.Add(input1);
if (input1 % 2 != 0)
{
if (isPrime_func(input1))
{
PrimeNumbers_decimal_list.Add(input1);
}
}
}
}
public static Boolean isPrime_func(decimal number)
{
decimal boundary = (decimal)Math.Floor(Math.Sqrt((double)number));
if (number == 1) return false;
if (number == 2) return true;
for (decimal i = 2; i <= boundary; ++i)
{
if (number % i == 0) return false;
}
return true;
}
每次我运行单击该按钮时,我都会得到不同的结果。我已经尝试了很多事情,但无法弄清楚为什么会发生这种情况。即使对于较低的范围,它也会发生。例如,在 100 个数字的范围内,它总是给出相同的结果。有时我的列表计数达到283138,有时达到283131和其他接近的数字。
另一个奇怪的是,当我评论检查偶数时,操作时间比这种模式短。怎么了?
当多个线程访问一个列表时,该列表必须是线程安全的,否则您将遇到很多问题。
.NET 提供了一些线程安全的集合,如 ConcurrentQueue<T>
类。
旁注:请考虑使用 Tasks
而不是线程。此外,.NET 框架通过 Parallel
类支持数据并行性。请考虑改用此类。
关于不检查数字是否偶数时的性能,我在本地进行了测试,得到了以下数字:
- 当我不检查数字是否偶数时,需要 ~76 秒。
- 当我检查数字是否偶数时,需要 ~66 秒。
因此,这与您的测量结果不符。这可能是由您的测量方式引起的。我用这样的Stopwatch
来衡量:
//...
Stopwatch sw = Stopwatch.StartNew();
thread1_thread.Start();
thread2_thread.Start();
thread3_thread.Start();
thread4_thread.Start();
thread1_thread.Join();
thread2_thread.Join();
thread3_thread.Join();
thread4_thread.Join();
long result = sw.ElapsedMilliseconds;
//...
顺便说一下,您可以执行以下操作,从而为您节省一些执行时间:
为 thread_func
方法中的每个线程创建一个普通的 List<T>
实例,以便您不会遇到多线程问题。然后,循环完成后,您可以从本地列表更新主列表。只有更新主列表必须是线程安全的。在这种情况下,我希望主列表是一个普通List<T>
,并且您使用 lock
关键字来同步对它的访问,因为您只需要更新它 4 次(线程数)。