【问题标题】:ELI5: How does converting an IEnumerable to a list or array avoid the performance penalty of multiple enumeration of IEnumerable?ELI5:将 IEnumerable 转换为列表或数组如何避免 IEnumerable 多次枚举的性能损失?
【发布时间】:2016-03-31 22:50:03
【问题描述】:

Resharper 经常抱怨这个:IEnumerable 可能有多个枚举。例如:

    private int ParseLoanNumber(IEnumerable<string> lines)
    {
        var loanNumber = 0;

        var item = lines.FirstOrDefault(l => l.StartsWith(" LN#    00"));

        if (item != null)
        {
            loanNumber = item.ParseInt(8, 10).GetValueOrDefault();
        }
        else
        {
            item = lines.FirstOrDefault(l => l.StartsWith(" LOAN-NO (CONT'D)  00"));
            if (item != null)
            {
                loanNumber = item.ParseInt(19, 10).GetValueOrDefault();
            }
        }
        // Yada yada...
    }

推荐的解决方案是将enumerable 转换为listarray,并对其进行迭代。

这让我很困惑。你仍然会枚举一些东西,两种类型(数组和列表)都实现了IEnumerable。那么这如何解决任何问题,或以任何方式提高性能?

【问题讨论】:

    标签: c# resharper ienumerable enumeration


    【解决方案1】:

    因为你可以这样写:

    public IEnumerable<int> GetNumbersSlowly()
    {
        for (var i = 0; i < 100; i++)
        {
            Thread.Sleep(10000); //Or retrieve from a website, etc
            yield return i;
        }
    }
    

    如果你这样使用它:

    var numbers = GetNumbersSlowly();
    foreach(var number in numbers) { 
        //Do something 
    }
    foreach(var number in numbers) { 
        //Do something 
    }
    

    这意味着每个数字完成的工作(睡眠)两次。对可枚举进行一次评估并将其存储在数组或列表中意味着您确定没有进行额外的处理来返回项目。

    既然你接的是IEnumerable&lt;string&gt;,你真的不知道来电者没有完成上述操作。

    如果您认为我的示例可能很少见或边缘情况,它也适用于以下情况:

    var someSource = new List<int> { 1, 2, 3, 4, 5 };
    var numbers = someSource.Select(s => s * 100000);
    

    现在每次迭代 numbers 时,您也在重新进行计算。在这种情况下,它的工作量并不大,为什么它比你需要的多(而且它是不平凡的工作并不少见)。

    【讨论】:

    • 仅举其他例子;一些IEnumerable&lt;T&gt; 根本不可重复——例如,它们可以从Socket 或外部源(如包装IDataReader 的数据库查询)中提取数据(例如,“dapper”允许这种类型的使用),或者他们可能会从 PRNG 等中提取数字
    • 所以如果我理解正确的话,不转换的性能损失来自延迟执行。这大致正确吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-06
    • 1970-01-01
    • 2020-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多