C# 处理迭代时出现时间跳跃问题
我有一个大型应用程序,它每秒处理大数据(大约5000000字节),并以字节压缩格式将信息发送给其他服务 我使用protobuf序列化来压缩字节和LZ4 这是我的密码:C# 处理迭代时出现时间跳跃问题,c#,C#,我有一个大型应用程序,它每秒处理大数据(大约5000000字节),并以字节压缩格式将信息发送给其他服务 我使用protobuf序列化来压缩字节和LZ4 这是我的密码: internal static byte[] ConvertToBytes(object data) { using (var uncompressedStream = new MemoryStream()) { SerializerModel.Seriali
internal static byte[] ConvertToBytes(object data)
{
using (var uncompressedStream = new MemoryStream())
{
SerializerModel.Serialize(uncompressedStream, data);
if (_typesToCompress.Contains(data.GetType()))
using (var compressedStream = new MemoryStream())
{
var head = DateTime.Now;
using (var lz4 = new LZ4Stream(compressedStream, LZ4StreamMode.Compress, LZ4StreamFlags.IsolateInnerStream))
using (var writer = new BinaryWriter(lz4))
writer.Write(uncompressedStream.ToArray());
if (uncompressedStream.Length > 0)
LogService.Enqueue(
$"Сжато {uncompressedStream.Length - compressedStream.Length} байт ({100 - 100.0 * compressedStream.Length / uncompressedStream.Length:0.0}% от объема) {data.GetType().Name} за {(DateTime.Now - head).TotalMilliseconds:0.0} мс",
LogTextType.Warning);
return compressedStream.ToArray();
}
return uncompressedStream.ToArray();
}
}
它工作得很好,我每秒花大约50毫秒来做这个手术
但有时(大约每10次迭代),我可以看到在我的代码的其他部分中发生了大的时间跳跃(300-500毫秒),但在转换或压缩过程中更经常发生在这一部分。下面是我看到的排放时间表
我认为这与LOH有关,但不确定。请帮我解决这个问题 所以,我花了几个小时玩GC选项,但没有达到目标。但最终我找到了适合我的解决方案
是的。我使用了这段代码并添加了返回字节块的属性(数组的大小是否会导致时间跳跃?可能与垃圾收集有关?您在每次迭代中创建一个新的大字节数组,而不是重用以前分配的空间。这会很快消耗内存。是的,清理LOH(保存大于85kb的对象)将需要一个完整的Gen3集合(使用PerfMon来解决这个问题),除非您开始管理自己的内存,否则您对此无能为力(而且,看看您的代码,我真的无法想象您会如何做)。在处理过程中,您是否有空闲到足以支付收集费用的时间点?如果有,您可以先发制人地安排时间。您还可以使用GC的LatencyModes和
GCSettings.LargeObjectHeapCompactionMode
。此外,如果您有一个时间非常关键的代码区域,则可以使用GC.TryStartNoGCRegion
以一种不应在关键部件期间发生GC操作的方式标记代码。
public IEnumerable<byte[]> Chunks
{
get
{
for (var i = 0; i < _chunks.Count - 1; i++)
{
yield return _chunks[i];
}
var last = new byte[_lastChunkPos];
Buffer.BlockCopy(_chunks[_chunks.Count - 1], 0, last, 0, _lastChunkPos);
yield return last;
}
}
internal static byte[] ConvertToBytes(object data)
{
using (var uncompressedStream = new ChunkedMemoryStream())
{
SerializerModel.Serialize(uncompressedStream, data);
if (_typesToCompress.Contains(data.GetType()))
using (var compressedStream = new ChunkedMemoryStream())
{
var head = DateTime.Now;
using (var lz4 = new LZ4Stream(compressedStream, LZ4StreamMode.Compress, LZ4StreamFlags.IsolateInnerStream))
using (var writer = new BinaryWriter(lz4))
{
foreach (var chunk in uncompressedStream.Chunks)
{
writer.Write(chunk);
}
}
if (uncompressedStream.Length > 0)
LogService.Enqueue(
$"Сжато {uncompressedStream.Length - compressedStream.Length} байт ({100 - 100.0 * compressedStream.Length / uncompressedStream.Length:0.0}% от объема) {data.GetType().Name} за {(DateTime.Now - head).TotalMilliseconds:0.0} мс",
LogTextType.Warning);
return compressedStream.ToArray();
}
return uncompressedStream.ToArray();
}
}