通過.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上開源。