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

11

我不确定我在测试中是否做错了什么,但从我的结果来看,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();
        }
    }
}
方法 平均时间 误差 标准偏差 分配空间
使用数组池 770.2微秒 2.27微秒 2.01微秒 1字节
使用内存池 1,714.6微秒 0.56微秒 0.50微秒 2,402字节

以上是我的测试代码及结果。内存池在一般情况下是否真的慢一些,或者我遗漏了什么?如果内存池确实更慢,那么它适用于哪些场景?

谢谢。


MemoryPool<T>是一个不错的选择,当你的代码需要分配内存块,并且你想通过重复使用已分配的内存来减轻GC的压力,而不是每次创建新的内存块时。 - stuartd
但是ArrayPool不是使用数组而不是内存<>执行相同的操作吗? - theflamingtiger
MemoryPool 分配它返回的 IMemoryOwner 实例。 - Bananach
1个回答

8

关于性能

重复调用memory.Span[i]是罪魁祸首。
GitHub上的源代码显示该属性getter后面有相当多的处理。

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

var span = memory.Span;

请见下方完整的代码块。

现在Mean数字几乎相等。

方法 平均值 误差 标准差 中位数 Gen 0 已分配内存
使用ArrayPool 333.4 微秒 2.34 微秒 5.15 微秒 331.0 微秒 - -
使用MemoryPool 368.6 微秒 7.08 微秒 5.53 微秒 366.7 微秒 0.4883 2,400 字节

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

关于分配内存的差异。

这是有意设计的。
已经有一个非常好的帖子解释了这个问题。


非常感谢您!但是无论如何,MemoryPool都比ArrayPool慢,有什么场景可以选择MemoryPool而不是ArrayPool呢? - theflamingtiger
2
这取决于您使用的数据;从那篇链接的帖子中可以看出:内存池可以由不同的来源支持,例如由非托管内存/由SafeHandle指向的内存支持。 - pfx
那么数组/内存所持有的数据类型会影响性能吗?这是否意味着数组/内存池更适合不同的数据类型? - theflamingtiger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接