在C#中,我运行了一个玩具代码,可以创建许多小对象(我知道理想情况下应该避免使用它 - 我只是想研究这个问题)。对于创建的相同总对象数,一个线程的运行速度比每个处理器一个线程(Parallel.For)快。
原子操作在于创建一个包含20k个小对象的列表(实际上是一个数组)(为简单起见,这里很长[4]):
private static void CreateList()
{
long[][] list = new long[20000][];
for (var i = 0; i < 20000; i++)
list[i] = new long[4];
}
如果我在一个线程中创建1000个列表,它将在1.5秒内运行。如果我创建1000个包含多个线程的列表(每个列表负责1000个列表的一个子集),它将以2s运行。
在以下情况下,行为基本相同:
你能解释一下原因吗?内存管理器中是否存在“锁定”。它与垃圾收集有关吗?
代码详情:
public static void Main()
{
Benchmark(1000, CreateList);
}
private static void Benchmark(int repeat, Action action)
{
Console.WriteLine("Single thread");
Benchmark(delegate ()
{
for (int i = 0; i < repeat; i++)
action();
});
Console.WriteLine("Multi thread");
Benchmark(delegate ()
{
Parallel.For(0, repeat, i => action());
});
}
private static void Benchmark(Action action)
{
for (int i = 0; i < 10; i++)
{
Stopwatch sw = new Stopwatch();
sw.Start();
action();
sw.Stop();
Console.WriteLine("Time : " + sw.Elapsed.TotalSeconds);
}
}
答案 0 :(得分:1)
尽管内存管理器使用某种信号量是正常的,但是具有许多内存分配的多线程应用程序使用默认的C#垃圾收集器非常糟糕。使用适当的垃圾收集器,情况会好很多。
你应该:
服务器GC将允许线程之间更好程度的并行化,因为内存分配是部分独立的。在这种情况下,性能可以在具有多个核心的计算机上发生根本变化。
简而言之,将其添加到项目的配置文件中:
<runtime>
<gcServer enabled="true"/>
<gcConcurrent enabled="false" />
</runtime>
您可以在Fundamentals of Garbage Collection中阅读有关服务器和工作站GC的详细信息。