C# capacity property[翻译&&学习]
2011-09-07 20:35 一一九九 阅读(423) 评论(0) 编辑 收藏 举报From:http://www.dotnetperls.com/capacity
虽然可以设置Collection的Capacity属性,你一定想知道为什么值得需要单独的设置Collection的Capacity属性把。这个选项用于调整分配的内存数量。这里我使用Dictinary和List来做个实验,测试一下他们的性能和影响。
测试结果:
class | capacity | time |
Dictionary | no capacity | 1350ms |
Dictionary | has capacity | 700ms |
Dictionary | const capacity | 760ms |
Dictionary | over-large capacity | 1005ms |
list | no | 1050ms |
list | accurate | 575ms |
Capacity Property
当不指定Capacity的时候,Collection会被重新分配内存多次,直到长到100大小的时候。(注:原文应该是错误的,Colleciton的时间耗费主要耗费在了内存的重新分配,并将原有的内存区块重新复制到新的内存区块上了,分配的容量是之前的Double)
What Mircrosoft says:
"The capacity of a Dictionary(TKey, TValue) is the number of elements that can be added to the Dictionary(TKey, TValue) before resizing is necessary. As elements are added to a Dictionary(TKey, TValue), the capacity is automatically increased as required by reallocating the internal array."
So why set capacity?
假如能够评估出来Collection的大小,指定最初的容量大小能够在往Dictonary中添加新的元素的时候消除重新分配调整容量大小的操作。
Is it important ?
由于.net重新调正后台的数组的大小的成本较高,并且会加倍Collection的添加元素时间。
Memory pressure
另外一个影响因素是当调整内存大小的时候造成的内存压力,这会导致GC回收的压力增大。
Benchmark capacity
下面是测试代码:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
class CapacityTest
{
/// <summary>
/// The number of iterations.
/// </summary>
static int _m = 100000;
/// <summary>
/// List of values we use for the test.
/// </summary>
List<string> _values = new List<string>();
public CapacityTest()
{
// 100 random strings for benchmarking.
for (int i = 0; i < 100; i++)
{
_values.Add(System.IO.Path.GetRandomFileName());
}
long t1 = Environment.TickCount;
A_Dictionary();
long t2 = Environment.TickCount;
B_DictionaryCapacity();
long t3 = Environment.TickCount;
C_DictionaryCapacity();
long t4 = Environment.TickCount;
D_DictionaryCapacity();
long t5 = Environment.TickCount;
E_List();
long t6 = Environment.TickCount;
F_ListCapacity();
long t7 = Environment.TickCount;
// Write dictionary times
Console.WriteLine(t2 - t1);
Console.WriteLine(t3 - t2);
Console.WriteLine(t4 - t3);
Console.WriteLine(t5 - t4);
// Write list times
Console.WriteLine(t6 - t5);
Console.WriteLine(t7 - t6);
Console.ReadLine();
}
void A_Dictionary()
{
// No capacity
for (int i = 0; i < _m; i++)
{
Dictionary<string, int> d = new Dictionary<string, int>();
foreach (string k in _values)
{
d.Add(k, 0);
}
}
}
void B_DictionaryCapacity()
{
// Capacity from collection Count
for (int i = 0; i < _m; i++)
{
Dictionary<string, int> d = new Dictionary<string, int>(_values.Count);
foreach (string k in _values)
{
d.Add(k, 0);
}
}
}
void C_DictionaryCapacity()
{
// Const capacity
for (int i = 0; i < _m; i++)
{
Dictionary<string, int> d = new Dictionary<string, int>(100);
foreach (string k in _values)
{
d.Add(k, 0);
}
}
}
void D_DictionaryCapacity()
{
// Huge capacity (1 order of magnitude too large)
for (int i = 0; i < _m; i++)
{
Dictionary<string, int> d = new Dictionary<string, int>(1000);
foreach (string k in _values)
{
d.Add(k, 0);
}
}
}
void E_List()
{
// No capacity
for (int i = 0; i < _m * 5; i++)
{
List<string> l = new List<string>();
foreach (string k in _values)
{
l.Add(k);
}
}
}
void F_ListCapacity()
{
// Exact capacity
for (int i = 0; i < _m * 5; i++)
{
List<string> l = new List<string>(100);
foreach (string k in _values)
{
l.Add(k);
}
}
}
}
Predict capacities
这里作者没有给出比较好的法子,大体上还是通过预估的方式进行。