【问题标题】:Poor multithreading performance in .Net.Net 中的多线程性能不佳
【发布时间】:2015-09-11 16:00:14
【问题描述】:

为什么我会从下面的代码中得到如此糟糕的性能?

以下命令行使用 16 个线程,负载为 60。 在我的机器上,这大约需要 31 秒才能完成(如果重新运行,会有一些细微的变化)

testapp.exe 16 60

使用 60 的负载,在 Microsoft Windows Server 2008 R2 Enterprise SP1 上,在 16 个 Intel Xeon E5-2670 @ 2.6 GHz CPU 上运行,我获得以下性能:

1 cpu - 305 秒

2 cpu - 155 秒

4 cpu - 80 秒

8 cpu - 45 秒

10 cpu - 41 秒

12 cpu - 37 秒

14 cpu - 34 秒

16 cpu - 31 秒

18 cpu - 27 秒

20 cpu - 24 秒

22 cpu - 23 秒

24 cpu - 21 秒

26 cpu - 20 秒

28 cpu - 19 秒

在这之后它变成了扁平线......

我使用 .Net 3.5、4、4.5 或 4.5.1 获得了大致相同的性能。

我了解 22 个 cpu 后性能下降,因为我只有 16 个。我不明白的是 8 cpus 后性能不佳。谁能解释一下?这正常吗?

private static void Main(string[] args)
{
    int threadCount;
    if (args == null || args.Length < 1 || !int.TryParse(args[0], out threadCount))
        threadCount = Environment.ProcessorCount;

    int load;
    if (args == null || args.Length < 2 || !int.TryParse(args[1], out load))
        load = 1;

    Console.WriteLine("ThreadCount:{0} Load:{1}", threadCount, load);

    List<Thread> threads = new List<Thread>();

    for (int i = 0; i < threadCount; i++)
    {
        int i1 = i;
        threads.Add(new Thread(() => DoWork(i1, threadCount, load)));
    }

    Stopwatch timer = Stopwatch.StartNew();

    foreach (var thread in threads)
    {
        thread.Start();
    }

    foreach (var thread in threads)
    {
        thread.Join();
    }

    timer.Stop();

    Console.WriteLine("Time:{0} seconds", timer.ElapsedMilliseconds/1000.0);
}

static void DoWork(int seed, int threadCount, int load)
{
    double[,] mtx = new double[3,3];

    for (int i = 0; i < ((100000 * load)/threadCount); i++)
    {
        for (int j = 0; j < 100; j++)
        {
            mtx = new double[3,3];

            for (int k = 0; k < 3; k++)
            {
                for (int l = 0; l < 3; l++)
                {
                    mtx[k, l] = Math.Sin(j + (k*3) + l + seed);
                }
            }
        }
    }
}

【问题讨论】:

  • 请注意,如果您比较喜欢,并查看 1、2、4、8、16 - 即错过了相对较小的 10、12、14 步,仍然有一个相对“大”从 45 -> 31 下降。
  • 我不确定您是否在那里对实际计算进行基准测试。看起来你真正的基准测试是并发堆分配。
  • GC花了多少时间?你用的是客户端GC还是服务端GC?
  • @displayName 在代码示例中,向下滚动。
  • 我建议对该实验进行两个(替代)更改:(1)在起始线程中预分配一些 new double[,] 数组,将每个数组传递给每个子线程,然后重用它而不是重新分配它循环或 (2) stackalloc double[3 * 3] 在循环中并使用它。否则,您可能会意外地对快速分配下的内存分配器或垃圾收集器的性能进行基准测试,而不是您的代码本身。

标签: c# .net multithreading performance


【解决方案1】:

请参阅英特尔方舟以获取XEON E5-2670

此特定处理器具有 8 个超线程物理内核。这就是为什么您会在 8 个线程之后看到性能下降的原因。调用 Environment.ProcessorCount 获得 16 个逻辑核心(每个物理核心 2 个逻辑核心,因为它们是超线程的)。

SuperUser 上的answered 也有类似的问题。

您可以尝试设置线程的亲和性,看看是否有区别,但调度程序通常可以很好地分配资源。

希望这会有所帮助。

【讨论】:

【解决方案2】:

并不是线程导致性能下降。但它是线程本身的“创造”。

您需要从操作系统线程池中借用一个已经创建的线程,而不是创建一个全新的线程。使用ThreadPool 类而不是使用new Thread()

【讨论】:

  • 我不是在快速循环中创建新线程,而是提前创建了我想使用的“工作”线程,但感谢您的回答
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-13
  • 1970-01-01
  • 2011-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多