我正在进行蒙特卡罗模拟。 工作在许多不同的机器之间进行分区(通常大约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();
}
}
设置:GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency
帮助了很多,但仍然存在很大的开销。
每个工人有244克的压头,远远超过模拟要求。 此外,几乎所有内容都被缓存,因此无需进行Gen2集合。
答案 0 :(得分:5)
.NET 4.6具有名为GC.TryStartNoGCRegion
的新GC功能。
这告诉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();
}
}
答案 1 :(得分:0)
-您可以在{#3}}的C#上使用非托管代码
-或使用托管的 GC块
GC.TryStartNoGCRegion(.)
{
// your critical code
} GC.EndNoGCRegion()
*不要忘记像以前的回答一样检查尝试条件
-this (GC.AddMemoryPressure)看GCSettings.LatencyMode
使用MS manual和gcServer参数在 *。config 文件(应用程序或计算机)中更改GC配置
<configuration>
<runtime>
<gcServer enabled="true"/>
<!-- OR / AND -->
<gcConcurrent enabled="true|false"/>
</runtime>
</configuration>