在通过IEnumerable T进行迭代之间的性能可以通过迭代来实现.和List< T> [英] Performance between Iterating through IEnumerable<T> and List<T>

查看:67
本文介绍了在通过IEnumerable T进行迭代之间的性能可以通过迭代来实现.和List< T>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天,我在遍历项目列表时遇到性能问题.经过诊断后,我终于找到了导致性能下降的原因.事实证明,通过IEnumerable<T>进行迭代比通过List<T>进行迭代花费的时间要多得多.请帮助我理解为什么IEnumerable<T>List<T>慢.

Today, I faced a problem with performance while iterating through a list of items. After done some diagnostic, I finally figured out the reason which slowed down performance. It turned out that iterating through an IEnumerable<T> took much more time than iterating through a List<T>. Please help me understand why IEnumerable<T> is slower than List<T>.

更新基准环境:

我正在使用NHibernate从数据库中获取项目的集合到IEnumerable<T>中,并对它的属性值求和.这只是一个简单的实体,没有任何引用类型:

I'm using NHibernate to fetch a collection of items from a database into an IEnumerable<T> and sum its property's value. This is just a simple entity without any reference type:

public SimpleEntity
{
    public int Id {get;set}
    public string Name {get;set}
    public decimal Price {get;set}
}

Public Test
{
    void Main()
    {
        //this query get a list of about 200 items
        IEnumerable<SimpleEntity> entities = from entity in Session.Query<SimpleEntity>
                                             select entity;

        decimal value = 0.0;
        foreach(SimpleEntity item in entities)
        {
             //this for loop took 1.5 seconds 
             value += item.Price;
        }

        List<SimpleEntity> lstEntities = entities.ToList();

        foreach(SimpleEntity item in lstEntities)
        {
             //this for loop took less than a milisecond
             value += item.Price;
        }
    }
}

推荐答案

List<T> IEnumerable<T>.遍历List<T>时,执行的操作序列与其他任何IEnumerable<T>相同:

List<T> is an IEnumerable<T>. When you are iterating through your List<T>, you are performing the same sequence of operations as you are for any other IEnumerable<T>:

  • 获取IEnumerator<T>.
  • 在枚举器上调用IEnumerator<T>.MoveNext().
  • 从IEnumerator接口中获取IEnumerator<T>.Current元素,而MoveNext()返回true.
  • 处置IEnumerator<T>.
  • Get an IEnumerator<T>.
  • Invoke IEnumerator<T>.MoveNext() on your enumerator.
  • Take the IEnumerator<T>.Current element from the IEnumerator interface while MoveNext() returns true.
  • Dispose of the IEnumerator<T>.

我们对List<T>的了解是它是一个内存中的集合,因此其枚举器上的MoveNext()函数将非常便宜.看来您的集合提供了一个枚举器,该枚举器的MoveNext()方法更昂贵,可能是因为它正在与某些外部资源(例如数据库连接)进行交互.

What we know about List<T> is that it is an in-memory collection, so the MoveNext() function on its enumerator is going to be very cheap. It looks like your collection gives an enumerator whose MoveNext() method is more expensive, perhaps because it is interacting with some external resource such as a database connection.

IEnumerable<T>上调用ToList()时,您正在运行集合的完整迭代,并使用该迭代将所有元素加载到内存中.如果您希望多次遍历同一集合,这是值得做的.如果您希望仅对集合进行一次遍历,那么ToList()就是一个错误的经济体:它所做的只是创建一个内存中的集合,以后必须对其进行垃圾回收.

When you call ToList() on your IEnumerable<T>, you are running a full iteration of your collection and loading all of the elements into memory with that iteration. This is worth doing if you expect to be iterating through the same collection multiple times. If you expect to iterate through the collection only once, then ToList() is a false economy: all it does is to create an in-memory collection that will later have to be garbage collected.

这篇关于在通过IEnumerable T进行迭代之间的性能可以通过迭代来实现.和List&lt; T&gt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆