【发布时间】: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)stackallocdouble[3 * 3]在循环中并使用它。否则,您可能会意外地对快速分配下的内存分配器或垃圾收集器的性能进行基准测试,而不是您的代码本身。
标签: c# .net multithreading performance