所以我优化了一个非常频繁使用字节数组的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#的性能吗? 如果是真的,为什么我的代码太慢了?是否有更好的方法来重用数组?
任何建议都会受到赞赏。谢谢。