我写了一个C#类,它正在填充"列表中的双打"有一些数据(不管数据是什么,现在它可能只是一些垃圾:)),用于测试目的:
以下是代码:
class test
{
public test()
{
_myListOfList = new List<List<double>>(1000000);
}
public void Run()
{
for (int i = 0; i < _myListOfList.Capacity; i++)
{
_myListOfList.Add(
new List<double>(3) { i, 10*i, 100*i}
); //Populate the list with data
}
}
private List<List<double>> _myListOfList;
}
我将此代码的执行速度与以下内容进行了比较:(用元组替换双重列表)
class test
{
public test()
{
_myListOfTuple = new List<Tuple<double, double, double>>(1000000);
}
public void Run()
{
for (int i = 0; i < _myListOfTuple.Capacity; i++)
{
_myListOfTuple.Add(
new Tuple<double, double, double>(i, 10 * i, 100 * i)
); //Populate the list with data
}
}
private List<Tuple<double, double, double>> _myListOfTuple;
}
事实证明使用元组似乎要快得多。我为不同的List大小运行了这段代码(从200,000个元素 - 列表中的> 5百万个元素),这是我得到的结果:
我无法真正理解这一点。为什么我会有如此显着的差异?使用存储相同类型对象的元组(此处加倍)并没有多大意义。我宁愿使用List /数组来做到这一点:我做错了什么?是否有一种方法可以使案例#1以比案例#2更快/更快的速度运行?
谢谢!
答案 0 :(得分:7)
new Tuple<double, double, double>(i, 10 * i, 100 * i)
和new List<double>(3) { i, 10*i, 100*i}
之间存在差异。
第一个是超级简单 - 只有3个任务:
public Tuple(T1 item1, T2 item2, T3 item3) {
m_Item1 = item1;
m_Item2 = item2;
m_Item3 = item3;
}
第二个实际上是由编译器转换为3个Add
方法调用:
var temp = new List<double>(3);
temp.Add(i);
temp.Add(10 * i);
temp.Add(100 * i);
Add
不仅仅是一项任务:
public void Add(T item) {
if (_size == _items.Length) EnsureCapacity(_size + 1);
_items[_size++] = item;
_version++;
}
运行更多代码,执行速度更慢。很简单..
答案 1 :(得分:2)
正如在@ Marcin的回答中所提到的,即使初始化List<T>
初始化列表IL仍然具有Add()
函数,即使您在构造期间最初指定列表Capacity也是如此。就像你在你的例子中所做的那样。
有没有办法让案例#1以比案例#2更快/更快的速度运行?
可能的解决方案可能是直接分配给成员:
list[0] =
list[1] =
list[2] =
在这种情况下,IL看起来像这样:
IL_0000: ldc.i4.3
IL_0001: newobj System.Collections.Generic.List<System.Double>..ctor
IL_0006: stloc.0 // list
IL_0007: ldloc.0 // list
IL_0008: ldc.i4.0
IL_0009: ldc.r8 00 00 00 00 00 00 F0 3F
IL_0012: callvirt System.Collections.Generic.List<System.Double>.set_Item
IL_0017: ldloc.0 // list
IL_0018: ldc.i4.1
IL_0019: ldc.r8 00 00 00 00 00 00 24 40
IL_0022: callvirt System.Collections.Generic.List<System.Double>.set_Item
IL_0027: ldloc.0 // list
IL_0028: ldc.i4.2
IL_0029: ldc.r8 00 00 00 00 00 00 59 40
IL_0032: callvirt System.Collections.Generic.List<System.Double>.set_Item
IL_0037: ret
set_Item
更快,因为它是一个简单的任务。
或者,使用简单的Array。性能应该更好。不过,有了这样的东西,比如A对B速度,只有经过具体测量才能得到真正的答案。