You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

内部函数租用ArrayPool数组后,如何正确归还至数组池?

数组池复用的优化方案探讨

场景描述

需要在内部函数中操作大型数组,操作结果由父函数消费(序列化为JSON通过HTTP返回)。原代码存在数组未归还至_defaultArrayPool、无法复用的问题:

public IActionResult ParentFunction()
{
    var returnedArray = InnerFunction(1000);
    return Ok(returnedArray.Take(1000));
}

public int[] InnerFunction(int count)
{
    var rentedArray = _defaultArrayPool.Rent(count);
    // 对rentedArray执行操作
    return rentedArray;
}

现有方案分析

方案1 - 父函数负责归还

缺点:Rent和Return调用分散在不同函数,易遗漏或出错

public IActionResult ParentFunction()
{
    int[] returnedArray = null;
    try
    {
        returnedArray = InnerFunction(1000);
        return Ok(returnedArray.Take(1000));
    }
    finally
    {
        if (returnedArray != null)
        {
            _defaultArrayPool.Return(returnedArray);
        }
    }
}

public int[] InnerFunction(int count)
{
    var rentedArray = _defaultArrayPool.Rent(count);
    // 对rentedArray执行操作
    return rentedArray;
}

方案2 - 父函数租用并归还,数组按引用传递

优点:Rent/Return在同一函数;缺点:父函数必须预先知晓数组长度,无法适配内部函数动态决定长度的场景

public IActionResult ParentFunction()
{
    var rentedArray = _defaultArrayPool.Rent(1000); // 若长度由内部函数决定则不可用
    try
    {
        InnerFunction(rentedArray, 1000);
        return Ok(rentedArray.Take(1000));
    }
    finally
    {
        if (rentedArray != null)
        {
            _defaultArrayPool.Return(rentedArray);
        }
    }
}

public void InnerFunction(int[] arr, int count)
{
    // 对arr执行操作
}

方案3 - 内部函数租用,父函数归还

优点:支持内部函数动态决定数组长度;缺点:仍存在Rent/Return分散的问题

public IActionResult ParentFunction()
{
    int[] rentedArray = null;
    try
    {
        var count = InnerFunction(out rentedArray);
        return Ok(rentedArray.Take(count));
    }
    finally
    {
        if (rentedArray != null)
        {
            _defaultArrayPool.Return(rentedArray);
        }
    }
}

public int InnerFunction(out int[] arr)
{
    int count = 1000; // 动态确定数组长度
    arr = _defaultArrayPool.Rent(count);
    // 对arr执行操作
    return count;
}

更优实现方案

方案4:使用回调委托,封装Rent/Return逻辑

将数组的租用、操作、归还逻辑统一在内部函数中,父函数只需提供结果处理的回调,彻底避免Rent/Return分散:

public IActionResult ParentFunction()
{
    IActionResult result = null;
    InnerFunction(1000, (array, count) => 
    {
        result = Ok(array.Take(count));
    });
    return result;
}

public void InnerFunction(int count, Action<int[], int> processResult)
{
    var rentedArray = _defaultArrayPool.Rent(count);
    try
    {
        // 对rentedArray执行操作
        processResult(rentedArray, count);
    }
    finally
    {
        _defaultArrayPool.Return(rentedArray);
    }
}

如果内部函数需要动态确定长度,只需调整参数:

public IActionResult ParentFunction()
{
    IActionResult result = null;
    InnerFunction((array, count) => 
    {
        result = Ok(array.Take(count));
    });
    return result;
}

public void InnerFunction(Action<int[], int> processResult)
{
    int count = DetermineDynamicCount(); // 动态计算长度
    var rentedArray = _defaultArrayPool.Rent(count);
    try
    {
        // 对rentedArray执行操作
        processResult(rentedArray, count);
    }
    finally
    {
        _defaultArrayPool.Return(rentedArray);
    }
}

private int DetermineDynamicCount()
{
    // 实际场景中动态计算所需长度
    return 1000;
}

方案5:自定义Disposable包装类,利用using自动归还

通过实现IDisposable接口,将数组的归还逻辑封装在Dispose方法中,借助C#的using语句自动释放,代码更简洁优雅:

public class PooledArray<T> : IDisposable
{
    private readonly ArrayPool<T> _pool;
    public T[] Array { get; }
    public int Count { get; }

    public PooledArray(ArrayPool<T> pool, int count)
    {
        _pool = pool;
        Count = count;
        Array = pool.Rent(count);
    }

    public void Dispose()
    {
        _pool.Return(Array);
    }
}

// 固定长度调用示例
public IActionResult ParentFunction()
{
    using var pooledArray = InnerFunction(1000);
    return Ok(pooledArray.Array.Take(pooledArray.Count));
}

public PooledArray<int> InnerFunction(int count)
{
    var pooled = new PooledArray<int>(_defaultArrayPool, count);
    // 对pooled.Array执行操作
    return pooled;
}

// 动态长度调用示例
public IActionResult ParentFunctionDynamic()
{
    using var pooledArray = InnerFunctionDynamic();
    return Ok(pooledArray.Array.Take(pooledArray.Count));
}

public PooledArray<int> InnerFunctionDynamic()
{
    int count = DetermineDynamicCount();
    var pooled = new PooledArray<int>(_defaultArrayPool, count);
    // 对pooled.Array执行操作
    return pooled;
}

方案对比与推荐

  • 回调委托方案:无需额外类,逻辑紧凑,Rent/Return完全封装在内部函数中,父函数只需关注结果处理,适合大多数场景。
  • Disposable包装类方案:借助using语法糖自动处理归还,代码可读性和维护性更强,适合需要复用数组池包装逻辑的场景。

这两种方案都解决了原方案中Rent/Return分散的问题,同时支持动态数组长度的场景,是更优的实现方式。

内容的提问来源于stack exchange,提问作者Maciej Pszczolinski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 16:17:12