List <T>与IEnumerable <T>

克里斯托斯(Christos)

我运行了以下控制台应用程序:

class Program
{
    static void Main(string[] args)
    {
        int n = 10000;

        Stopwatch s = new Stopwatch();
        s.Start();
        List<int> numbers = GetListNumber(n);
        foreach (var number in numbers)
        {

        }
        s.Stop();
        Console.WriteLine(s.Elapsed);
        Console.WriteLine();

        s.Restart();
        foreach (var number in GetEnumerator(n))
        {

        }
        s.Stop();
        Console.WriteLine(s.Elapsed);
        Console.ReadKey();
    }

    static List<int> GetListNumber(int n)
    {
        List<int> numbers = new List<int>();
        for (int i = 0; i < n; i++)
            numbers.Add(i);
        return numbers;
    }

    static IEnumerable<int> GetEnumerator(int n)
    {
        for (int i = 0; i < n; i++)
            yield return i;
    }
}

为了比较时间,我们需要遍历一个集合的元素,以及是否最好使用aList或an来构建这个集合IEnumerable令我惊讶的是,结果是和分别为00:00:00.0005504List和00:00:00.0016900 IEnumerable我原本以为第二种方法IEnumerable会更快,因为这些值是动态创建的,我们不必一次将它们中的每一个添加一次,例如在a的情况下,List然后遍历它。

请问有人能解释一下我的区别吗?为什么我们有这种行为,却没有相反的行为。

在此先感谢您的帮助!

首先,测试方式并不能真正为您提供有关性能差异的有用印象。10000个项目的迭代确实太短了;您已经看到了这一点,因为您获得的结果以微秒为单位。相反,您应始终尝试从中获取多个秒数。此外,你应该始终运行在相同的测试多次在序次,然后取平均值出来。这样,您就可以消除随机影响,并获得更稳定的结果(另请参见大数定律)。

但是,是的,迭代生成器函数可能比列表慢。这是由于不同的原因:首先,当您从暂停执行的函数中获取项目时,实际上会导致很多上下文切换。我不确定生成器函数的优化程度如何,但是您仍然必须以某种方式处理它们,因此您确实要受到惩罚。

其次,列出内部使用的数组,这些数组会根据需要动态调整大小。因此,最后,当您遍历列表时,即遍历数组。您正在遍历内存中的一系列数字。这将永远比其他任何东西都快。

最大的区别在于内存方面,这应该使您在完整列表中考虑生成器功能。创建列表时,您将快速生成所有项目,将它们放入内存,然后再次快速遍历它们。但是,您也将它们全部存储在内存中。因此,根据项目数量,这可能意味着高昂的成本。尤其是当您只需要访问一次项目时,这通常是不值得的。另一方面,生成器功能仅需要单个项目的内存,因此从内存角度来看,这是非常有效的。

最后,尽管存在速度差异,但这可能无关紧要。很少有应用程序会变慢,因为您决定在某个地方使用生成器函数。应用程序的瓶颈更有可能出现在其他地方,最有可能发生在I / O或网络操作中,因此,在出现问题之前,您真的不应该在意它。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章