【问题标题】:Parallel functions return different results in C#并行函数在 C# 中返回不同的结果
【发布时间】:2016-02-17 18:54:27
【问题描述】:

我的 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 和其他接近的数字。

另一个奇怪的是,当我评论检查偶数时,操作比这种模式花费的时间更短。怎么了?

【问题讨论】:

  • threadNumbers_listPrimeNumbers_decimal_list 可能不是线程安全的。
  • 我创建该列表只是为了检查是否所有迭代都发生了!
  • PrimeNumbers_decimal_list 怎么样?另外,您如何等待线程完成?你用Thread.Join吗?
  • 我检查 VS 事件并等待所有线程退出并检查应用程序 cpu 使用情况,然后单击另一个显示 primenumberlist 计数的按钮
  • 我创建了多线程多素数函数但无法解决!

标签: c# multithreading primes


【解决方案1】:

当多个线程访问一个列表时,该列表必须是线程安全的,否则您将遇到很多问题。

.NET 提供了一些thread-safe collections,例如ConcurrentQueue&lt;T&gt; 类。

旁注:请考虑使用Tasks 而不是线程。此外,.NET 框架supports data parallelism via the Parallel class。考虑改用此类。

关于不检查数字是否为偶数时的性能,我在本地进行了测试,得到了以下数字:

  • 如果我不检查数字是否为偶数,大约需要 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&lt;T&gt; 实例,这样您就不会遇到多线程问题。然后在循环完成后,您可以从本地列表更新主列表。只有更新主列表必须是线程安全的。在这种情况下,我希望主列表是一个普通的List&lt;T&gt;,并且您使用lock 关键字来同步对它的访问,因为您只需要更新它 4 次(线程数)。

【讨论】:

  • PrimeNumbers_decimal_list的定义是什么?是List&lt;T&gt;吗?您可以将其更改为ConcurrentQueue&lt;T&gt; 并使用Enqueue 方法而不是Add 方法。
  • 好的,谢谢,我去看看。 List PrimeNumbers_decimal_list = new List();
  • 是的!非常感谢@Yacoub 结果问题已经解决了:)
  • 为什么检查偶数不会加快运算速度,还会变慢呢?
  • 不客气。即使您使用了ConcurrentQueue&lt;T&gt; 类,偶数慢问题是否也会发生?
猜你喜欢
  • 2012-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多