Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 列表<&燃气轮机;最好使用最大容量的init,只使用其中的一小部分,或者使用没有容量的init_C#_.net_List - Fatal编程技术网

C# 列表<&燃气轮机;最好使用最大容量的init,只使用其中的一小部分,或者使用没有容量的init

C# 列表<&燃气轮机;最好使用最大容量的init,只使用其中的一小部分,或者使用没有容量的init,c#,.net,list,C#,.net,List,我有一个列表,我正在初始化它为空,我将在解析数据时在循环中填充这个结构。我知道将插入此列表的条目的最大可能数量。现在让我们假设1000。然而,在我解析了1000个条目之后,我可能只在列表中添加了2个条目。因此,我应该用1000的容量初始化列表,还是不指定容量,只添加几个条目。然而,最终可能会加上所有1000个。性能方面的最佳方法是什么?其实并不重要。不要微优化。只有在你有一个好主意的情况下才设置容量,它大致上是你需要的数量。在引擎盖下,列表每次增长都会翻倍,因此增长的数量是O(log(n))。它

我有一个
列表
,我正在初始化它为空,我将在解析数据时在循环中填充这个结构。我知道将插入此列表的条目的最大可能数量。现在让我们假设1000。然而,在我解析了1000个条目之后,我可能只在列表中添加了2个条目。因此,我应该用1000的容量初始化列表,还是不指定容量,只添加几个条目。然而,最终可能会加上所有1000个。性能方面的最佳方法是什么?

其实并不重要。不要微优化。只有在你有一个好主意的情况下才设置容量,它大致上是你需要的数量。在引擎盖下,列表每次增长都会翻倍,因此增长的数量是
O(log(n))
。它应该相当有效。

也许最好的办法是妥协。将列表初始化为256左右。

如果它的变化真的那么大,那么您可能不想设置容量。对于大多数集合,容量会在满足时加倍(我相信默认容量为16),因此在填充时,您的容量将非常接近您的最大容量。

考虑到您的列表一开始很小,最好不要初始化它。它将使代码更易于阅读,而不会对性能造成任何明显的影响。

首先,您应该以最自然、可维护和可读的方式实现它。在这种情况下,只需创建一个新的
列表
(接受默认容量)并将对象添加到其中。然后,如果您的应用程序不符合性能规范,您要做的就是对其进行评测。如果通过分析发现这是应用程序中的瓶颈,那么您可以尝试对其进行优化。如果您的应用程序符合您的性能规范,或者如果此特定部分不是瓶颈,则忽略它


第二,有时候实现细节很重要,下面就是一个例子。
List
的实现方式是一个动态增长的数组,它以一定的容量开始,并在每次需要重新增长时将大小加倍。这意味着,如果您将
n
对象添加到新创建的列表中,将出现
O(logn)
重新增长,您最多会浪费
O(n)
空间。除非你的系统内存很紧(也许你正在手机上运行.NET CF),否则这没什么大不了的。从性能的角度来看,解析条目可能比重新增长要花费更多的时间。因此,这也不太可能是一个因素。

首先,假设我不是在这样一个地方来写答案,我第一次来找它,但我写一个,只是为了建议,也为了得到你的意见

添加数据时列表的作用:

public void Add(T item) {
    if (_size == _items.Length) EnsureCapacity(_size + 1);
    _items[_size++] = item;
    _version++;
}

private void EnsureCapacity(int min) {
    if (_items.Length < min) {
        int newCapacity = _items.Length == 0? _defaultCapacity : _items.Length * 2;
        // Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.
        // Note that this check works even when _items.Length overflowed thanks to the (uint) cast
        if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength;
        if (newCapacity < min) newCapacity = min;
        Capacity = newCapacity;
    }
}
显然,这不是一个简单的标志改变操作,只是让更多的项目进来,因为链表会做什么(老实说,我总是把列表看作链接列表)。现在我可以说用列表,我有更好的读取性能,更少的写入性能。(但我不确定我说的是什么,有人确认我们在执行写入和一次性读取操作时是否应该使用LinkedList…)。因此,我们可以看到,它创建了一个新数组,并将项逐个复制到新列表中

因此,我的建议如下:

  • 正如@jason所说,我们不需要考虑将一个值传递给它,因为我们只能在列表中运行一次写操作
  • 如果列表的权重很小,例如,仅仅增加列表大小的几次迭代不会有多大作用,例如,正如大家所说的,如果它是2变成4,8…首先,我们只增加了三倍的大小,其次,我们只复制了少量的数据。同样,无论代码放在哪里,我们都可以忽略它,或者我希望如此
  • 但是,如果您从数据库复制几千个数据,并且它从开始开始,2->4->8->16->32->64->128->256->512->1024->2048->。。。 直到知道我们有10个时间增加数组大小,如果我们认为拷贝只是拷贝引用的单个操作,除了机器代码中需要做的其他几件事之外,我们将有4094个时间将数据从一个数组拷贝到另一个数组,并且还消耗了等待GC所需的一半空间(在图形应用程序中,RAM可能很重要,但我无法为其编写示例)。。。 因此,如果同时调用这样的代码,则性能可能会急剧下降。因此,我可以考虑做以下几项:如果我知道一个数字,例如,我知道我有X项,并且这些项目可以引用0~2,我可以考虑通过X或X* 2,如果需要的话,它只会增长一次。(请告诉我你的意见)

  • 在完成想法3时,每个列表的加倍似乎是合理的,而且无论你做什么,你只能增加一半的时间,而完成整个操作只需要这一半的~两个,因此如果你不同时启动多个线程/任务,或者一个接一个地启动大量列表,你可能会忽略它。

  • 我还发现:
    private const int\u defaultCapacity=4;


    注意:如果使用最大容量,正如上面所说,它存储的空间等于2G元素所需的空间量(正如上面所说:
    //在遇到溢出之前,允许列表增长到最大可能容量(~2G元素)。
    ),这不是您想要初始化列表的数量,即使您的代码只运行一次,它看起来像ram中有太多的直接(线性/并行)数据(正如数据结构所认为的,如果C#没有做任何比我们的书中所说的更新的事情),分配也可能需要相当长的时间(我不知道这个过程)所以如果你真的不知道需要多少,我就不推荐了,而且我也这么认为
    public int Capacity {
        get {
            Contract.Ensures(Contract.Result<int>() >= 0);
            return _items.Length;
        }
        set {
            if (value < _size) {
                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_SmallCapacity);
            }
            Contract.EndContractBlock();
    
            if (value != _items.Length) {
                if (value > 0) {
                    T[] newItems = new T[value];
                    if (_size > 0) {
                        Array.Copy(_items, 0, newItems, 0, _size);
                    }
                    _items = newItems;
                }
                else {
                    _items = _emptyArray;
                }
            }
        }
    }