【问题标题】:why single thread code is faster than multi-threadding?为什么单线程代码比多线程快?
【发布时间】:2018-02-16 07:19:13
【问题描述】:

我写了一个代码,它以单线程和多线程方式执行求和函数,如下所示:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;

namespace ParallelFor
{
    class Program
    {
        static void Main()
        {
            Console.WriteLine("Program started");
            var step_time = Stopwatch.StartNew();
            step_time.Start();

            double R1 = 0.0;
            double R2 = 0.0;
            double R3 = 0.0;
            var t1 = new Thread(() => TestCounter(2000, ref R1, 1));
            var t2 = new Thread(() => TestCounter(2000, ref R2, 2));
            var t3 = new Thread(() => TestCounter(2000, ref R3, 3));
            t1.Start();
            t2.Start();
            t3.Start();
            do
            {

            } while (t1.IsAlive == true || t2.IsAlive == true || t3.IsAlive == true);
            Console.WriteLine("inside R1: {0}", R1);
            Console.WriteLine("inside R2: {0}", R2);
            Console.WriteLine("inside R3: {0}", R3);
            Console.WriteLine("Program finished");
            step_time.Stop();
            Console.WriteLine("multi-thread last {0} (MilSec)\n", step_time.ElapsedMilliseconds);

            step_time.Reset();

            step_time.Start();
            R1 = 0.0;
            R2 = 0.0;
            R3 = 0.0;
            TestCounter(2000, ref R1, 1);
            TestCounter(2000, ref R2, 2);
            TestCounter(2000, ref R3, 3);
            Console.WriteLine("inside R1: {0}", R1);
            Console.WriteLine("inside R2: {0}", R2);
            Console.WriteLine("inside R3: {0}", R3);
            step_time.Stop();
            Console.WriteLine("single thread last {0} (MilSec)\n", step_time.ElapsedMilliseconds);
            Console.ReadLine();
        }
        static void TestCounter(int counter, ref double result, int No)
        {
            for (int i = 0; i < counter + 1; i++)
                for (int j = 0; j < counter; j++)
                    for (int k = 0; k < counter; k++)
                        result += (double)i;
        }
    }
}

我发现单线程部分,最后更短! (我用 counter=10000 运行代码,结果是一样的!) 为什么单线程解析速度更快?!?!

【问题讨论】:

  • 你不应该把线程的开始算作并行持续时间的一部分...
  • 首先,您不应该使用 while Thread.IsAlive 循环,而应使用 Thread.Join 或其他更好的方法来等待所有线程完成。其次,您在什么 CPU/硬件上运行它,这对并行线程性能很重要。

标签: c# multithreading


【解决方案1】:

我认为设置线程和等待线程完成的开销高于在多个线程上运行代码的收益。 此外,如果您启动的线程数多于可用内核数,您的代码会因为上下文切换次数过多而变慢。

您可以尝试的一项优化是使用Monitor.Wait() 调用摆脱手动同步。您可以手动创建Thread 对象(与CPU 内核一样多),启动它们,然后通过调用Thread.Join() 等待线程完成。这样您的线程中就不需要任何同步代码:

Thread[] threads = new Thread[NumCores];  

for (int i = 0; i < NumCores; i++)  
{  
   threads[i] = new Thread(MyThread);  

   threads[i].Start(threadData);  
}  

for (int i = 0; i < NumCores; i++){  
   threads[i].Join(); 
}

【讨论】:

    【解决方案2】:

    问题很可能是Cache Thrashing。我将 TestCounter 方法更改为以下内容:

    static void TestCounter(int counter, ref double result, int No)
    {
      double internalResult = 0;
      for (int i = 0; i < counter + 1; i++)
        for (int j = 0; j < counter; j++)
          for (int k = 0; k < counter; k++)
            internalResult += (double)i;
    
      result += internalResult;
    }
    

    这里,首先将值累加到一个局部变量中,最后才写入传递的结果变量。因此,线程大部分时间都在其本地堆栈上工作,而不是在其他线程也访问的内存位置(分别是缓存行)上。

    有了这个改变,我几乎得到了预期因子 3 的加速。

    【讨论】:

      猜你喜欢
      • 2013-11-22
      • 1970-01-01
      • 2014-07-21
      • 1970-01-01
      • 2016-08-09
      • 2017-12-26
      • 1970-01-01
      • 1970-01-01
      • 2015-07-09
      相关资源
      最近更新 更多