昨天刚说了PowerCollections强大,今天就这么随手拿来一看发现不少问题,不光是设计,还有效率方面的.
(PS: PowerCollections是从<<CLR Via C#>>中看到的,Jeff说其的BigList在count>100的时候有更优秀的效率,而且里面提供了很多丰富的集合类.)
public
abstract
class
CollectionBase
<
T
>
: ICollection
<
T
>
, ICollection
{
public virtual void CopyTo(T[] array, int arrayIndex)
{
// code 1
}
void ICollection.CopyTo(Array array, int index)
{
// code 2
}
}
code 1 跟code 2的代码完全一样,足有10多行重复代码,不知其是Copy&Parse 还是重新写了一遍,汗!
既然有了一个CopyTo的方法,并且标明为virtual ,可被子类覆盖了,为什么还要显示实现ICollection.CopyTo, 再汗!
public
abstract
class
ListBase
<
T
>
: CollectionBase
<
T
>
, IList
<
T
>
, IList
{
public override void CopyTo(T[] array, int arrayIndex)
{
base.CopyTo(array, arrayIndex);
}
}
ListBase.CopyTo()啥事也没干,却又override一遍,这不摆明徒增开销嘛,继续汗!
再来看看CopyTo的代码,一看再吃一惊竟然是用foreach循环+set Arrary做的,这样的效率能忍受吗?
public
virtual
void
CopyTo(T[] array,
int
arrayIndex)
{
// check parameters
int i = 0;
foreach (object o in (ICollection)this)
{
if (i >= count)
break;
array.SetValue(o, index);
++index;
++i;
}
}
我们看看FCL中的List<T>.CopyTo()怎么做的.
public void CopyTo(T[] array, int arrayIndex)
{
Array.Copy(this._items, 0, array, arrayIndex, this._size);
}
Arry.Copy不知道多少人熟习,里面究竟是怎么实现的我是看不太懂,但效率是没话说滴.
自己测试了一下在集合count = 1000000,循环100次测试结果如下
Debuge 结果:
Release结果:
BigList在Debug跟Release下表现的性能差别很大,不知是什么原因(BigLsit<T>继承自ListBase<T>,因此其调用CollectionBase<T>.CopyTo()需要查两次Method Table,在Debug下应该要记录下调试信息,不好优化可能慢一点,纯属猜测,有哪位大大知道正确缘由,请高知,谢谢!)
但BigList相差List还是蛮大的,如果将count变的更小点,差距将更大.不知道"BigList在count>100的时候有更优秀的效率",在哪体现了.
看看PowerCollections的doc:
BigList<T> provides a list of items, in order, with indices of the items ranging from 0 to one less than the count of items in the collection. BigList<T> is optimized for efficient operations on large (>100 items) lists, especially for insertions, deletions, copies, and concatinations.
PS: 昨天说到PowerCollections有些出自Jeff之手,但今天看源代码作者好像都是Peter Golde, sorry for it.不过Peter Golde也应该是位大师级人物吧. 看来不可全信别人的代码啊,即使出自大师之手,还是应该用平静的心态去研究啊.
完整的测试代码
class Program
{
const int COUNT_NUB = 10000;
const int LOOP_NUB = 100;
static Stopwatch sw = null;
static string[] copyArray = new string[COUNT_NUB];
static void Main(string[] args)
{
List<string> list = new List<string>();
BigList<string> bigList = new BigList<string>();
for (int i = 0; i < COUNT_NUB; i++)
{
list.Add(i.ToString());
bigList.Add(i.ToString());
}
TestCopeTo(list);
List_CopyTo(list);
BigList_CopyTo(bigList);
Console.Read();
}
private static void TestCopeTo(List<string> list)
{
Stopwatch sw = Stopwatch.StartNew();
int loopCount = LOOP_NUB;
while (loopCount > 0)
{
CopyTo<string>(list, copyArray, 0);
loopCount--;
}
sw.Stop();
Console.WriteLine("CopyTo Method past: {0}s", sw.Elapsed);
}
private static void List_CopyTo(List<string> list)
{
sw = Stopwatch.StartNew();
int loopCount = LOOP_NUB;
while (loopCount > 0)
{
list.CopyTo(copyArray, 0);
loopCount--;
}
sw.Stop();
Console.WriteLine("List<T> CopyTo Method: {0}s", sw.Elapsed);
}
private static void BigList_CopyTo(BigList<string> bigList)
{
sw = Stopwatch.StartNew();
int loopCount = LOOP_NUB;
while (loopCount > 0)
{
bigList.CopyTo(copyArray, 0);
loopCount--;
}
sw.Stop();
Console.WriteLine("BigList<T> CopyTo Method: {0}s", sw.Elapsed);
}
public static void CopyTo<T>(List<T> list, T[] array, int arrayIndex)
{
int index = arrayIndex, i = 0;
foreach (T item in list)
{
if (i >= list.Count)
break;
array[index] = item;
++index;
++i;
}
}
}
后一篇:第2枪小谈RemoveALL算法