在C#中重用数组

时间:2014-07-22 09:58:41

标签: c# arrays performance optimization reusability

所以我优化了一个非常频繁使用字节数组的C#程序,我编写了一种循环池来重用必须由GC收集的数组。像那样:

public class ArrayPool<T>
{
    private readonly ConcurrentDictionary<int, ConcurrentBag<T[]>> _pool;

    public ArrayPool()
    {
        _pool = new ConcurrentDictionary<int, ConcurrentBag<T[]>>();
    }

    public ArrayPool(int capacity)
    {
        _pool = new ConcurrentDictionary<int, ConcurrentBag<T[]>>(4, capacity);
        for (var i = 1; i <= capacity; i++)
        {
            _pool.TryAdd(i, new ConcurrentBag<T[]>());
        }
    }

    public T[] Alloc(int capacity)
    {
        if (capacity < 1)
        {
            return null;
        }
        if (_pool.ContainsKey(capacity))
        {
            var subpool = _pool[capacity];
            T[] result;
            if (subpool != null) return subpool.TryTake(out result) ? result : new T[capacity];
            subpool = new ConcurrentBag<T[]>();
            _pool.TryAdd(capacity, subpool);
            _pool[capacity] = subpool;
            return subpool.TryTake(out result) ? result : new T[capacity];
        }
        _pool[capacity] = new ConcurrentBag<T[]>();
        return new T[capacity];
    }

    public void Free(T[] array)
    {
        if (array == null || array.Length < 1)
        {
            return;
        }
        var len = array.Length;
        Array.Clear(array, 0, len);
        var subpool = _pool[len] ?? new ConcurrentBag<T[]>();
        subpool.Add(array);
    }

}

我还写了一些代码来测试它的性能:

const int TestTimes = 100000;
const int PoolCapacity = 1000;
public static ArrayPool<byte> BytePool;
static void Main()
{
    BytePool = = new ArrayPool<byte>(PoolCapacity);
    var watch = Stopwatch.StartNew();
    for (var i = 1; i <= TestTimes; i++)
    {
        var len = (i % PoolCapacity) + 1;
        var array = new byte[len];
    }
    watch.Stop();
    Console.WriteLine("Traditional Method: {0} ms.", watch.ElapsedMilliseconds);
    watch = Stopwatch.StartNew();
    for (var i = 1; i <= TestTimes; i++)
    {
        var len = (i % PoolCapacity) + 1;
        var array = BytePool.Alloc(len);
        BytePool.Free(array);
    }
    watch.Stop();
    Console.WriteLine("New Method: {0} ms.", watch.ElapsedMilliseconds);
    Console.ReadKey();
}

我认为如果程序每次都可以重用内存而不是malloc它应该更快,但事实证明我的代码比以前慢了大约10倍:

  

传统方法:31毫秒。   新方法:283毫秒。

因此,重新生成数组可以提高C#的性能吗? 如果是真的,为什么我的代码太慢了?是否有更好的方法来重用数组?

任何建议都会受到赞赏。谢谢。

2 个答案:

答案 0 :(得分:5)

您应该查看新的System.Buffers包。

答案 1 :(得分:1)

新的ArrayPool类将处理此问题。