You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义Where()实现为何比LINQ Where()性能更低?

Why Your Custom MyWhere Underperforms LINQ's Built-in Where

Great question! Let's dive into exactly why your custom MyWhere implementation isn't as fast as the official LINQ Where, and how their performance stacks up in different scenarios.

Key Issues in Your Implementation

Your code works, but it has a few design choices that hurt performance and deviate from LINQ's behavior:

  • Unnecessary Empty Sequence Check
    Your code immediately calls enumerator.MoveNext() to check if the sequence is empty, and throws an exception if it is. This is a double whammy:

    1. It adds an extra, unneeded MoveNext() call even when the sequence has elements.
    2. It changes core behavior: LINQ's Where doesn't throw on empty sequences—it simply returns an empty enumerator. Throwing exceptions is also inherently expensive, so this adds overhead when dealing with empty inputs.
  • No Specialized Optimizations for Common Collections
    The built-in Where is optimized for specific IEnumerable<T> implementations like arrays, List<T>, or HashSet<T>. For example, if you pass an array, LINQ uses direct index access instead of an enumerator, which avoids the overhead of enumerator state management and method calls. Your implementation uses the generic enumerator for all sources, missing out on these performance gains.

  • Suboptimal Enumerator Flow
    Your do-while loop starts with a pre-fetched element (from the initial MoveNext()). While this works, it doesn't align with LINQ's lazy execution model perfectly. LINQ only fetches elements when the consumer calls MoveNext() on the resulting enumerator, which avoids pre-fetching elements that might never be used (e.g., if the consumer stops enumerating early).

Performance Comparison

Let's break down how these differences play out in real scenarios:

1. Empty Sequences

  • Your MyWhere: Immediately throws an InvalidOperationException, which involves exception stack trace generation and cleanup—this is slow.
  • LINQ Where: Returns an empty enumerator with almost zero overhead, no exceptions thrown.

2. Small/Medium Sequences

For sequences where you might only consume a few elements (e.g., using First() or Take(5)):

  • Your implementation pre-fetches the first element upfront, which wastes cycles if that element doesn't match the predicate and you stop enumerating early.
  • LINQ fetches elements on-demand, so it only processes exactly what's needed.

3. Large Sequences (e.g., Arrays/Lists)

Here's where the gap widens:

  • LINQ switches to optimized index-based iteration for collections like arrays, which is significantly faster than using an enumerator (fewer method calls, no state tracking).
  • Your implementation uses the generic enumerator regardless of the source type, which adds consistent overhead per element processed.

Example Performance Test

If you run a quick test with a large array:

var largeArray = Enumerable.Range(0, 1_000_000).ToArray();

// LINQ Where
var linqStopwatch = Stopwatch.StartNew();
var linqCount = largeArray.Where(x => x % 2 == 0).Count();
linqStopwatch.Stop();

// Custom MyWhere
var customStopwatch = Stopwatch.StartNew();
var customCount = largeArray.MyWhere(x => x % 2 == 0).Count();
customStopwatch.Stop();

Console.WriteLine($"LINQ Where: {linqStopwatch.ElapsedMilliseconds}ms");
Console.WriteLine($"Custom MyWhere: {customStopwatch.ElapsedMilliseconds}ms");

You'll typically see LINQ finish in half the time (or less) compared to your implementation, thanks to array-specific optimizations.

Fixing Your Implementation

To align closer to LINQ's performance and behavior, you'd want to:

  • Remove the empty sequence check (let the consumer handle empty results if needed).
  • Add null checks for source and predicate (throw ArgumentNullException upfront, like LINQ does).
  • Consider adding overloads for specific collection types to leverage optimized iteration.

内容的提问来源于stack exchange,提问作者HelloWorld

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:23:54