我正在运行蒙特卡罗模拟。
工作被分配给许多不同的机器(通常约150台)。
每次迭代后,每个工作人员都会向服务器发送其结果。 在从所有工作人员获取结果后,服务器计算更新并将其发送回所有工作人员。
这个周期重复进行100-1000次。
服务器不能计算更新直到所有工作者都发送了他们的结果,所以如果99个工作者需要1秒钟完成一次迭代,而第100个工作者需要10秒钟,那么整个迭代就需要10秒钟。
问题在于GC会随机地在某些迭代的某些工作者上启动,从而导致这些工作者需要更长的时间,从而减缓整个过程的速度。
例如,在迭代#1期间,工人#58花费了10秒钟,而其他工人则花费了8秒钟。在迭代#2期间,不同的工作者需要更长的时间等等。
这增加的开销似乎约为20-30%。
我想做的是指示GC在迭代期间不执行任何收集。 只收集每10次迭代后(以便所有工作人员同步其收集),或在发送结果之后,在从服务器获取更新之前进行收集。
以下是我尝试做的伪代码:
每次迭代后,每个工作人员都会向服务器发送其结果。 在从所有工作人员获取结果后,服务器计算更新并将其发送回所有工作人员。
这个周期重复进行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
有很大的帮助,但仍存在显着的开销。
每个工作线程都有244gb的内存,比模拟所需的要多得多。此外,几乎所有内容都被缓存,因此不需要进行Gen2收集。