ArrayPoolWrapper簡潔、安全的ArrayPool

通過.NET中的 ArrayPool 我們可以實現(xiàn)對T[]類型的池化,避免頻繁的分配內(nèi)存和GC,以提升性能。鑒于已有不少博客介紹ArrayPool的具體原理,本文不會涉及其實現(xiàn)細(xì)節(jié)。本文聚焦使用中的痛點,并提供簡潔的封裝方案以提升ArrarPool使用的便捷性。

ArrayPool本身的使用方式比較簡單:

using System.Buffers;

var pool = ArrayPool<int>.Shared.Rent(4);
// 其他邏輯
ArrayPool<int>.Shared.Return(pool);

為了確保在發(fā)生異常時能夠釋放資源,通常需要寫成如下形式的樣板代碼:

int[] pool = null!;
try
{
    pool = ArrayPool<int>.Shared.Rent(4);
    // 其他邏輯
}
finally
{
    if (pool != null)
    {
        ArrayPool<int>.Shared.Return(pool);
    }
}

以上寫法會是我們的代碼中充斥大量的樣板代碼和大量的嵌套,影響代碼后續(xù)的可讀性和可維護(hù)性。

接下來我們在原ArrayPool的基礎(chǔ)上稍加封裝,以實現(xiàn)簡潔、安全的使用ArrayPool的目標(biāo),封裝后的使用只需一行代碼,效果如下:

using var pool = new ArrayPoolWrapper<int>(5);

具體實現(xiàn)代碼如下:

public struct ArrayPoolWrapper<T> : IDisposable
{
    private int _index = -1;
    private bool _disposed = false;
    private readonly int _capacity;

    private readonly T[] _pool;

    public ArrayPoolWrapper(int capacity)
    {
        if (capacity <= 0)
        {
            throw new ArgumentOutOfRangeException(nameof(capacity), "The capacity must be greater than 0.");
        }

        this._capacity = capacity;
        _pool = ArrayPool<T>.Shared.Rent(capacity);
    }


    public void Add(T info)
    {
        ThrowIfDisposed();

        _index++;
        if (_index >= _capacity)
        {
            _index--;

            throw new InvalidOperationException("The array pool has reached its capacity.");
        }

        _pool[_index] = info;
    }

    public void Dispose()
    {
        ThrowIfDisposed();
        _disposed = true;

        ArrayPool<T>.Shared.Return(_pool);
    }


    private readonly void ThrowIfDisposed()
    {
        if (_disposed)
        {
            throw new ObjectDisposedException(nameof(ArrayPoolWrapper<T>));
        }
    }
}

我們還可以通過封裝來實現(xiàn)更多的擴(kuò)展API,如:RemoveLastOne以及基于Span的切片操作:

public struct ArrayPoolWrapper<T> : IDisposable
{
    public readonly int Count => _index + 1;
    public readonly Span<T> Values => _pool.AsSpan()[..Count];


    public void RemoveLastOne()
    {
        ThrowIfDisposed();

        if (Count <= 0)
        {
            throw new InvalidOperationException("The array pool is empty.");
        }

        _pool[_index] = default!;
        _index--;
    }
}

使用示例如下:

using var pool = new ArrayPoolWrapper<int>(8);
for (var i = 0; i < 8; i++)
{
    pool.Add(i);
}

pool.RemoveLastOne();
Console.WriteLine(pool.Count);

foreach (var i in pool.Values[1..3])
{
    Console.WriteLine(i);
}

完整的實現(xiàn)代碼已在Github上開源。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容