我很困惑为什么将GCSettings.LatencyMode
设置为GCLatencyMode.LowLatency
会对执行时间产生负面影响?
请考虑以下代码。请注意,我在线程池中有足够的线程,所以我确保这里没有引入延迟。此外,我在这台机器上有足够的内存。 Interactive
和LowLatency
之间的差异导致LowLatency
的执行时间增加了3倍。
class Program
{
static void Main(string[] args)
{
//capture current latency mode
var currentLatencyMode = GCSettings.LatencyMode;
//set low latency mode to minimize garbage collection
GCSettings.LatencyMode = GCLatencyMode.LowLatency;
var watch = new Stopwatch();
var numberTasksToSpinOff = 4;
var numberItems = 20000;
var random = new Random((int)DateTime.Now.Ticks);
var dataPoints = Enumerable.Range(1, numberItems).Select(x => random.NextDouble()).ToList();
var workers = new List<Worker>();
//structure workers
for (int i = 1; i <= numberTasksToSpinOff; i++)
{
workers.Add(new Worker(i, dataPoints));
}
//start timer
watch.Restart();
//parallel work
if (workers.Any())
{
var processorCount = Environment.ProcessorCount;
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = processorCount };
Parallel.ForEach(workers, parallelOptions, DoSomeWork);
}
//stop timer
watch.Stop();
//reset latency mode
GCSettings.LatencyMode = currentLatencyMode;
Console.WriteLine($"Time it took to complete in Milliseconds: {watch.ElapsedMilliseconds}");
Console.WriteLine("Press key to quit");
Console.ReadLine();
}
private static void DoSomeWork(Worker worker)
{
Console.WriteLine($"WorkerId: {worker.WorkerId} -> New Tasks spun off with in Thread Id: {Thread.CurrentThread.ManagedThreadId}");
var indexPos = 0;
foreach (var dp in worker.DataPoints)
{
var subset = worker.DataPoints.Skip(indexPos).Take(worker.DataPoints.Count - indexPos).ToList();
indexPos++;
}
}
}
public class Worker
{
public int WorkerId { get; set; }
public List<double> DataPoints { get; set; }
public Worker(int workerId, List<double> dataPoints)
{
WorkerId = workerId;
DataPoints = dataPoints;
}
}
答案 0 :(得分:3)
这里没有免费的午餐,垃圾收集者必须做一份工作,并试图考虑你的顾虑。然而,没有一种尺寸适合所有(特别是当试图突破其极限时)。
要回收对象,垃圾收集器必须停止所有执行 应用程序中的线程。在某些情况下,例如当 应用程序检索数据或显示内容,一个完整的垃圾 收集可以在关键时刻发生并阻碍性能。您 可以通过设置来调整垃圾收集器的侵入性
GCSettings.LatencyMode
属性之一System.Runtime.GCLatencyMode
值
更多
LowLatency 会抑制第2代集合并仅执行 第0代和第1代集合。它只能用于短时间 时间在较长时期内,如果系统处于内存压力之下, 垃圾收集器将触发一个集合,可以简单地 暂停应用程序并中断对时间要求严格的操作。这个 设置仅适用于工作站垃圾回收。
在低延迟期间,除非发生以下情况,否则将抑制第2代集合:
使用低延迟的指南
使用LowLatency模式时,请考虑以下准则:
尽可能缩短低延迟的时间段。
避免在低延迟期间分配大量内存。由于垃圾回收,可能会发生内存不足通知 回收更少的物品。
在低延迟模式下,最小化您所分配的数量,特别是在大对象堆上的分配和 固定物品。
注意可能分配的线程。因为LatencyMode属性设置是进程范围的,所以您可以生成一个 任何可能分配的线程的OutOfMemoryException。
- 醇>
...
根据指南(考虑到您之前的问题,How to properly parallelize worker tasks?),您显然是在尝试将其用于预期的理想操作条件。
我认为最重要的一点是1和3,显然垃圾收集器要么被gc.collect
命令强制清理,要么觉得它需要清理你正在使用的大量内存分配,即11演出。
这里的关键是,不知道垃圾收集器的确切内部和工作情况,并且确切地知道你在做什么以及为什么,你的问题可能没有一个理想的答案来说除了“在你的你的情况会影响执行时间“