为什么 MemoryPool 比 ArrayPool 更慢且分配更多?

the*_*ger 11 c# heap-memory .net-core

我不完全确定我在测试中是否做错了什么,但从我的结果来看,MemoryPool 始终比 ArrayPool 慢并且分配更多内存,因为无论如何您都可以将 Array 类型转换为 Memory,那么使用 MemoryPool 有什么意义呢?

using System.Buffers;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Attributes;

BenchmarkRunner.Run<test>();

[MemoryDiagnoser]
public class test
{
    [Benchmark]
    public void WithArrayPool()
    {
        ArrayPool<int> pool = ArrayPool<int>.Shared;

        for (int z = 0; z < 100; z++)
        {
            var memory = pool.Rent(2347);
            
            for (int i = 0; i < memory.Length; i++)
            {
                memory[i] = i + 1;
            }

            int total = 0;

            for (int i = 0; i < memory.Length; i++)
            {
                total += memory[i];
            }

            pool.Return(memory);
        }
    }

    [Benchmark]
    public void WithMemoryPool()
    {
        MemoryPool<int> pool = MemoryPool<int>.Shared;

        for (int z = 0; z < 100; z++)
        {
            var rentedArray = pool.Rent(2347);
            var memory = rentedArray.Memory;
            
            for (int i = 0; i < memory.Length; i++)
            {
                memory.Span[i] = i + 1;
            }

            int total = 0;

            for (int i = 0; i < memory.Length; i++)
            {
                total += memory.Span[i];
            }

            rentedArray.Dispose();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
方法 意思是 错误 标准差 已分配
带数组池 770.2 我们 2.27 我们 2.01 我们 1乙
带内存池 1,714.6 美元 0.56我们 0.50我们 2,402 乙

我的测试代码及其结果如上所述。内存池实际上一般来说速度较慢还是我遗漏了一些东西?如果 MemoryPool 实际上更慢,那么它有什么用途?

谢谢。

pfx*_*pfx 8

关于表演。

反复的调用memory.Span[i]就是罪魁祸首。GitHub
上的源代码显示,在该属性 getter 后面发生了相当多的处理。

不要重复该调用,而是将该调用的结果存储在变量中

var span = memory.Span;
Run Code Online (Sandbox Code Playgroud)

请参阅下面的完整代码块。

现在Mean数字几乎相等。

方法 意思是 错误 标准差 中位数 第0代 已分配
带数组池 333.4 我们 2.34 我们 5.15我们 331.0 我们 - -
带内存池 368.6 我们 7.08 我们 5.53我们 366.7 我们 0.4883 2,400 B

[Benchmark]
public void WithMemoryPool()
{
    MemoryPool<int> pool = MemoryPool<int>.Shared;

    for (int z = 0; z < 100; z++)
    {
        var rentedArray = pool.Rent(2347);
        var memory = rentedArray.Memory;
        var span = memory.Span; 

        for (int i = 0; i < memory.Length; i++)
        {
            span[i] = i + 1;
        }

        int total = 0;

        for (int i = 0; i < memory.Length; i++)
        {
            total += span[i];
        }

        rentedArray.Dispose();
    }
}
Run Code Online (Sandbox Code Playgroud)

关于分配内存的差异。

这是设计使然。
已经有一篇非常好的文章解释了这一点。

  • 这取决于您使用的数据;来自该链接的帖子:“内存池可能由不同的来源支持,例如由 SafeHandle 指向的非托管内存/内存”。 (2认同)