最近对.NET项目进行性能优化,在开启编译器优化的前提下,对List
首先我们创建两个不同类型的List对象,各自塞了5000000个简单元素:1
2
3
4
5
6
7var listInt = new List<int>();
var listString = new List<String>();
for (var i = 0; i < 5000000; i++)
{
listInt.Add(1);
listString.Add("1");
}
在此我们分别通过foreach, for-loop, 和List1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41CodeTimer.Time("foreach int", 10, () =>
{
foreach (var item in listInt)
{
}
});
CodeTimer.Time("List.Foreach int", 10, () =>
{
listInt.ForEach(s =>
{
});
});
CodeTimer.Time("for loop int", 10, () =>
{
for (int i = 0; i < listInt.Count; i++)
{
}
});
CodeTimer.Time("foreach string", 10, () =>
{
foreach (var item in listString)
{
}
});
CodeTimer.Time("List.Foreach string", 10, () =>
{
listString.ForEach(s =>
{
});
});
CodeTimer.Time("for loop string", 10, () =>
{
for (int i = 0; i < listString.Count; i++)
{
}
});
运行结果如图:
从结果中很容易得出结论,三种遍历,无论是对值类型还是引用类型,都是for-loop更高效。
原因
至于原因,我们先来看看List
- 调用GetEnumerator并在托管堆上创建一个Enumerator实例,将会引起垃圾回收。
- 每次迭代时调用Enimerator的MoveNext方法
- 每次迭代时给Current成员赋值
接着我们看看List1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public void ForEach(Action<T> action) {
if( action == null) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
}
Contract.EndContractBlock();
int version = _version;
for(int i = 0 ; i < _size; i++) {
if (version != _version && BinaryCompatibility.TargetsAtLeast_Desktop_V4_5) {
break;
}
action(_items[i]);
}
if (version != _version && BinaryCompatibility.TargetsAtLeast_Desktop_V4_5)
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
不难发现ForEach方法也是对for-loop的封装,只不过每次都要执行一次Action委托,比for-loop慢是肯定的。
最后,如果大家追求性能的话,建议尽量使用for-loop对List