C# 处理迭代时出现时间跳跃问题

C# 处理迭代时出现时间跳跃问题,c#,C#,我有一个大型应用程序,它每秒处理大数据(大约5000000字节),并以字节压缩格式将信息发送给其他服务 我使用protobuf序列化来压缩字节和LZ4 这是我的密码: internal static byte[] ConvertToBytes(object data) { using (var uncompressedStream = new MemoryStream()) { SerializerModel.Seriali

我有一个大型应用程序,它每秒处理大数据(大约5000000字节),并以字节压缩格式将信息发送给其他服务

我使用protobuf序列化来压缩字节和LZ4

这是我的密码:

    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();
        }
    }