首页 > 基础资料 博客日记

ArrayPoolWrapper简洁、安全的ArrayPool

2026-04-28 13:30:02基础资料围观1

文章ArrayPoolWrapper简洁、安全的ArrayPool分享给大家,欢迎收藏极客资料网,专注分享技术知识

通过.NET中的 ArrayPool 我们可以实现对T[]类型的池化,避免频繁的分配内存和GC,以提升性能。鉴于已有不少博客介绍ArrayPool的具体原理,本文不会涉及其实现细节。本文聚焦使用中的痛点,并提供简洁的封装方案以提升ArrarPool使用的便捷性。

 

ArrayPool本身的使用方式比较简单:

using System.Buffers;
​
var pool = ArrayPool<int>.Shared.Rent(4);
// 其他逻辑
ArrayPool<int>.Shared.Return(pool);

为了确保在发生异常时能够释放资源,通常需要写成如下形式的样板代码:

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

以上写法会是我们的代码中充斥大量的样板代码和大量的嵌套,影响代码后续的可读性和可维护性。

 

接下来我们在原ArrayPool的基础上稍加封装,以实现简洁、安全的使用ArrayPool的目标,代码如下:

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

封装后的使用只需一行代码,效果如下:

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

我们还可以通过封装来实现更多的扩展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);
} 

完整的实现代码已在Github上开源。


文章来源:https://www.cnblogs.com/Cwj-XFH/p/19939421
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐

标签云