繁体   English   中英

在这个例子中,为什么使用比列表更快的元组?

[英]Why is using a Tuple faster than a List in this example?

我写了一个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;
}

我将此代码的执行速度与以下内容进行了比较:(用元组替换double的列表)

    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更快/更快的速度运行?

谢谢!

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++;
}

运行更多代码,执行速度更慢。 非常简单..

正如在@ Marcin的回答中提到的那样,即使初始化List<T>初始化列表IL仍然在内部具有Add()函数,即使您在构造期间最初指定列表的容量也是如此。 就像你在你的例子中所做的那样

是否有一种方法可以使案例#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更快,因为它是一个简单的赋值。

或者,使用简单的数组 表现应该更好。 不过,有了这样的东西,比如A vs B速度,只有经过具体测量才能得到真正的答案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM