【问题标题】:Creating byte array without initializing with 0s [duplicate]创建字节数组而不用0初始化[重复]
【发布时间】:2019-04-01 15:57:34
【问题描述】:

对于网络相关的框架,我需要大量的byte[] 缓冲区来读取和写入数据。创建新字节数组时,CLR 将使用0 初始化所有值。对于与流一起使用的缓冲区,这似乎是不必要的开销:

var buffer = new byte[65536];

var read = await stream.ReadAsync(buffer, 0, buffer.Length);

有没有办法在 C# 中创建 byte[] 数组而不用 0 初始化所有值?可能通过调用malloc 样式方法?我确定这个问题已经得到解答,但我没有找到任何线索。

【问题讨论】:

  • 不,没有。您可以做的是使用 pool 缓冲区,因此开销只发生一次。然后,您需要确保您的逻辑处理数组中可能包含“旧”数据的事实。
  • 虽然重用数组是一个好的开始,但我怀疑您可能还想研究“管道”,它可以为您提供ArrayPool<byte> 的所有优点,而且还有更多,包括更好的消费模型,以及使用非连续缓冲区的能力;管道是支撑令人印象深刻的 Kestrel 性能的 API。你说“网络相关框架”——在这种情况下,Pipelines.Sockets.Unofficial (nuget) 有一个 SocketPipe 桥用于直接消费,如果你需要中介,还有一个 StreamPipe 桥(例如,@987654328 @)
  • @MarcGravell:非常感谢!尤其是 API 的 PositionOfAdvance 在标记化/解析请求时似乎是梦想。在实现 HTTP/2 时,我将看看管道。
  • @Gene 注意:HTTP/2(客户端和服务器)作为 .NET Core 3 的一部分被添加;如果您想了解更多使用管道的详细信息/示例,我已经在博客中广泛介绍了它
  • @MarcGravell:嗯,这个项目的想法是自己实现 HTTP 协议,主要是出于教育原因。但我肯定会看看那里的接口。要达到每秒 700 万个请求,还有很长的路要走 :)

标签: c# .net streaming clr .net-standard


【解决方案1】:

感谢mjwills链接,我偶然发现了System.BuffersArrayPool<T>

static void Main(string[] args)
{
    var pool = ArrayPool<byte>.Create();

    var watch = new Stopwatch();
    watch.Start();

    Parallel.For(0, 1000000, (i) =>
    {
        //DoSomethingWithBuffers();
        DoSomethingWithPooledBuffers(pool);
    });

    Console.WriteLine(watch.ElapsedMilliseconds);
}

private static int DoSomethingWithBuffers()
{
    var buffer = new byte[65536];
    return buffer.Length;
}

private static int DoSomethingWithPooledBuffers(ArrayPool<byte> pool)
{
    var buffer = pool.Rent(65536);

    var length = buffer.Length;

    pool.Return(buffer);

    return length;
}

这有很大的不同(发布模式):

  • DoSomethingWithBuffers:3264 毫秒
  • DoSomethingWithPooledBuffers:470 毫秒

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-11
    • 1970-01-01
    • 2015-07-25
    • 2016-11-20
    • 2016-04-02
    • 1970-01-01
    • 2011-08-01
    相关资源
    最近更新 更多