C# LINQ扩展方法的顺序不影响性能?

C# LINQ扩展方法的顺序不影响性能?,c#,.net,linq,C#,.net,Linq,我感到惊讶的是,我是否预先编写或附加LINQ扩展方法显然无关紧要 通过以下方式进行测试: hugeList.Where(x=>x.Text.Contains(“10000”)).FirstOrDefault() hugeList.FirstOrDefault(x=>x.Text.Contains(“10000”) var hugeList=可枚举范围(15000000) .Select(i=>new{ID=i,Text=“Item”+i}); var sw1=新系统.Diagnostics.St

我感到惊讶的是,我是否预先编写或附加LINQ扩展方法显然无关紧要

通过以下方式进行测试:

  • hugeList.Where(x=>x.Text.Contains(“10000”)).FirstOrDefault()
  • hugeList.FirstOrDefault(x=>x.Text.Contains(“10000”)

    var hugeList=可枚举范围(15000000)
    .Select(i=>new{ID=i,Text=“Item”+i});
    var sw1=新系统.Diagnostics.Stopwatch();
    var sw2=新系统.Diagnostics.Stopwatch();
    sw1.Start();
    对于(int i=0;i x.Text.Contains(“10000”)).FirstOrDefault();
    sw1.Stop();
    sw2.Start();
    对于(int i=0;i x.Text.Contains(“10000”);
    sw2.Stop();
    var result1=String.Format(“FirstOrDefault之后:{0}FirstOrDefault之前:{1}”,sw1.appeased,sw2.appeased);
    //结果1:00:00:03.3169683之后的第一个默认值:00:00:03.0463219之前的第一个默认值
    sw2.Restart();
    对于(int i=0;i<1000;i++)
    hugeList.FirstOrDefault(x=>x.Text.Contains(“10000”);
    sw2.Stop();
    sw1.Restart();
    对于(int i=0;i<1000;i++)
    其中(x=>x.Text.Contains(“10000”)).FirstOrDefault();
    sw1.Stop();
    var result2=String.Format(“FirstOrDefault之前:{0}FirstOrDefault之后:{1}”,sw2.appeased,sw1.appeased);
    //结果2:00:00:03.6833079之前的FirstOrDefault:00:03.1675611之后的FirstOrDefault
    //之后的平均值:3.2422647之前的平均值:3.3648149(所有秒)
    
  • 我猜想,在
    Where
    前面加上前缀会比较慢,因为它必须找到所有匹配的项,然后取第一个,前面的
    FirstOrDefault
    可能会生成第一个找到的项

    Q:有人能解释一下我为什么走错了路吗

    Where()
    方法使用延迟执行,并将根据请求提供下一个匹配项。也就是说,
    Where()
    不会计算并立即返回所有候选对象的序列,而是在迭代时一次提供一个

    由于
    FirstOrDefault()
    在第一项之后停止,这将导致
    Where()
    也停止迭代

    FirstOrDefault()
    视为停止执行
    Where()
    ,就好像它执行了一个
    break
    。当然,这并不是那么简单,但本质上是因为
    FirstOrDefault()
    一旦找到一个项就会停止迭代,
    Where()
    不需要再继续

    <>当然,这是一个简单的例子,在<代码> >())/<代码>子句中应用<代码> FraseDebug(< /代码>),如果您有其他子句,意味着需要考虑所有项,这可能会产生影响,但这在使用<代码>何处> .FrStReDebug()“组合或只是< /COD> FrStReDebug()”中具有谓语。 我会猜,在哪里进行前置会比较慢,因为它必须找到所有匹配的项,然后取第一个,前面的FirstOrDefault可能会生成第一个找到的项。有人能解释为什么我走错了方向吗

    你走错了方向,因为你的第一句话根本不正确
    其中
    不需要在获取第一个匹配项之前查找所有匹配项<代码>其中
    按需获取匹配的项目;如果你只要求第一个,它只会得到第一个。如果你只要求前两个,它只会得到前两个

    乔恩·斯基特在舞台上表演得不错。假设你有三个人。第一个人有一副洗过的牌。第二个人的t恤上写着“where card is red”。第三个人戳了戳第二个人,说“给我第一张卡”。第二个人一次又一次地戳第一个人,直到第一个人交出一张红牌,第二个人再把红牌递给第三个人。第二个人没有理由继续戳第一个人;任务完成了

    现在,如果第二个人的t恤上写着“按等级升序”,那么我们的情况就完全不同了。现在,第二个人确实需要从第一个人那里得到每一张牌,以便在将第一张牌交给第三个人之前找到牌组中最低的牌


    现在,这将为您提供必要的直觉,告诉您什么时候顺序对性能有影响。“给我红牌,然后对它们进行排序”的净结果与“对所有牌进行排序,然后给我红牌”的净结果完全相同,但前者的速度要快得多,因为您不必花费任何时间对要丢弃的黑牌进行排序。

    可能重复的@KirkWoll:这怎么可能是一个远程重复?这里的OP询问操作顺序;您引用的副本询问的是延迟执行。@Robert,我不认为这比
    更有趣。FirstOrDefault
    计算受
    约束的延迟查询。其中
    只使用一个结果。由于延迟执行,因此不必对序列的全部内容进行评估。对我来说,这是重复的,因为我认为这里的OP不知道延迟执行。一旦你有了这些知识,这种行为对我来说是显而易见的。好问题!这需要更多的投票。@KirkWoll:对你重复的评论的回复太晚了:如果一个重复的评论可以间接解释另一个问题,但如果这个问题是相同的,那么它就不是重复的。如果有人问“为什么一只鸟不会从天上掉下来”,这是“翅膀的好处是什么”的翻版吗?不,你需要知道问题的答案才能找到“重复”,所以它不是一个;)您可能应该在其中的某个地方提到,顺序在某些操作中确实很重要,就像Eric一样。有些案例并不重要,比如这一个,但是说它不重要是错误的。谢谢你生动的解释。但是我仍然有问题去理解延期执行的本质。我不知道我是不是必须
    var hugeList = Enumerable.Range(1, 50000000)
        .Select(i => new { ID = i, Text = "Item" + i });
    
    var sw1 = new System.Diagnostics.Stopwatch();
    var sw2 = new System.Diagnostics.Stopwatch();
    
    sw1.Start();
    for(int i=0;i<1000;i++)
        hugeList.Where(x => x.Text.Contains("10000")).FirstOrDefault();
    sw1.Stop();
    
    sw2.Start();
    for(int i=0;i<1000;i++)
        hugeList.FirstOrDefault(x => x.Text.Contains("10000"));
    sw2.Stop();
    
    var result1 = String.Format("FirstOrDefault after: {0} FirstOrDefault before: {1}", sw1.Elapsed,  sw2.Elapsed);
    //result1: FirstOrDefault after: 00:00:03.3169683 FirstOrDefault before: 00:00:03.0463219
    
    sw2.Restart();
    for (int i = 0; i < 1000; i++)
        hugeList.FirstOrDefault(x => x.Text.Contains("10000"));
    sw2.Stop();
    
    sw1.Restart();
    for (int i = 0; i < 1000; i++)
        hugeList.Where(x => x.Text.Contains("10000")).FirstOrDefault();
    sw1.Stop();
    
    var result2 = String.Format("FirstOrDefault before: {0} FirstOrDefault after: {1}", sw2.Elapsed, sw1.Elapsed);
    //result2: FirstOrDefault before: 00:00:03.6833079 FirstOrDefault after: 00:00:03.1675611
    
    //average after:3.2422647 before: 3.3648149 (all seconds)