在某些情况下防止GC集合以提高性能

Mic*_*hal 2 .net c# performance garbage-collection

我正在进行蒙特卡罗模拟.工作在许多不同的机器之间进行分区(通常大约150个).

每次迭代后,每个工作人员将其结果发送到服务器.从所有工作人员获得结果后,服务器会计算更新并将其发送回所有工作人员.

该循环重复100-1000次迭代.

在所有工作人员发送结果之前,服务器无法计算更新,因此如果99名工作人员需要1秒完成迭代而第100名工作人员需要10秒,那么整个迭代需要10秒.

问题是GC会在某些迭代中随机启动一些工作人员,因此会导致这些工作人员花费更多时间,从而减慢整个过程.

例如,在#1迭代期间,#58工作者需要10秒,其他工作人员需要8秒.在迭代#2中,不同的工作者需要更长的时间,依此类推.

这增加的开销似乎约为20-30%.

我想做的是指示GC在迭代发生时不要进行任何收集.仅收集每次10次迭代(以便所有工作人员同步其集合),或在发送结果后收集,以及从服务器获取更新之前收集.

这是我正在尝试做的伪代码:

public void Algorithm()
{
  for (var iteration = 0; iteration < 1000; iteration++)
  {
     PerformIteration(); //don't do any GC inside.
     SendResults();
     //Now there is a small time window to perform GC
     //before results from the server arrive (thats usually sub 0.5sec window)
     WaitForUpdate();
  }
}
Run Code Online (Sandbox Code Playgroud)

设置:GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency帮助了很多,但仍然有很大的开销.

每个工人有244克的压头,远远超过模拟要求.此外,几乎所有内容都被缓存,因此无需进行Gen2集合.

Yuv*_*kov 6

.NET 4.6具有一个名为的新GC功能GC.TryStartNoGCRegion.

这告诉GC尝试运行这段代码而不进行任何集合:

如果指定数量的内存可用,则尝试在执行关键路径期间禁止垃圾收集,并控制垃圾收集器是否在最初可用的内存不足时执行完全阻塞垃圾收集.

当您调用它时,您可以指示GC在执行GC之前可以分配多少内存.它必须小于或等于短暂的段大小:

public void Algorithm()
{
   for (var iteration = 0; iteration < 1000; iteration++)
   {
        // allow the GC to allocate 4kb
        if (GC.TryStartNoGCRegion(4096, true))
        {
            try
            {
                PerformIteration();
                SendResults();
            }
            finally
            {
                GC.EndNoGCRegion();
            }
        }

      //Now there is a small time window to perform GC
      //before results from the server arrive (thats usually sub 0.5sec window)
      WaitForUpdate();
   }
}
Run Code Online (Sandbox Code Playgroud)