【发布时间】:2012-04-17 08:18:39
【问题描述】:
希望这是一篇有效的帖子,它结合了 C# 问题和硬件。
我正在对我们的服务器进行基准测试,因为我们发现了 quant 库(用 C# 编写)的性能问题。我用一些简单的 C# 代码模拟了相同的性能问题——执行非常重的内存使用。
下面的代码是从线程池中生成的一个函数,最多有 32 个线程(因为我们的服务器有 4 个 CPU,每个有 8 个内核)。
这一切都在 .Net 3.5 上
问题是我们得到了截然不同的性能。我运行以下函数 1000 次。代码运行的平均时间可能是 3.5 秒,但最快的只有 1.2 秒,最慢的只有 7 秒——对于完全相同的功能!
我已经根据时间绘制了内存使用情况,似乎与 GC 启动没有任何关联。
我确实注意到的一件事是,在单线程中运行时,时间是相同的,并且没有明显的偏差。我还测试了受 CPU 限制的算法,并且时间也相同。这让我们怀疑内存总线是否无法应对。
我想知道这可能是另一个 .net 或 C# 问题,还是与我们的硬件有关?如果我使用 C++ 或 Java,这会是同样的体验吗?我们使用的是 4x Intel x7550 和 32GB 内存。一般有什么办法可以解决这个问题吗?
Stopwatch watch = new Stopwatch();
watch.Start();
List<byte> list1 = new List<byte>();
List<byte> list2 = new List<byte>();
List<byte> list3 = new List<byte>();
int Size1 = 10000000;
int Size2 = 2 * Size1;
int Size3 = Size1;
for (int i = 0; i < Size1; i++)
{
list1.Add(57);
}
for (int i = 0; i < Size2; i = i + 2)
{
list2.Add(56);
}
for (int i = 0; i < Size3; i++)
{
byte temp = list1.ElementAt(i);
byte temp2 = list2.ElementAt(i);
list3.Add(temp);
list2[i] = temp;
list1[i] = temp2;
}
watch.Stop();
(代码只是为了强调内存)
我会包含线程池代码,但我们使用了非标准线程池库。
编辑:我已将“size1”减少到 100000,这基本上不会使用太多内存,但我仍然会得到很多抖动。这表明不是传输的内存量,而是内存抢占的频率?
【问题讨论】:
-
在您的基准测试期间是否有任何其他进程正在运行?甚至操作系统也需要 CPU 时间。如果您在基准测试期间使用所有虚拟内核,那么您实际上(请原谅双关语)保证在您的测试期间不相关的进程将占用 CPU 时间。
-
除了推测之外,我们没有足够的信息来做任何事情。也就是说,我的钱花在你的“非标准线程池库”上,没有分配足够的线程来并行运行它。如果您运行 50 个副本并且仅分配 20 个线程(例如),则 10 次迭代将不得不(平均)等待 2 次其他迭代完成以释放线程。这可能是您看到的偏差的原因。
-
只是一个想法:由于您似乎知道列表的大小,因此您应该将其传递给构造函数(或仅使用数组)。然后,如果基础数组,则避免重新分配。
-
线程之间有同步吗?
-
+1 对 Brian Rasmussen 的建议:您可能在内存分配和移动内容上花费了大量时间。
标签: c# .net performance memory memory-management