"关闭变量会使性能稍差".怎么样?

Nik*_*wal 10 c#

在给出SO问题的答案时,我被告知我的解决方案将引入一个变量闭包,因此性能稍差.所以我的问题是:

  1. 如何关闭?
  2. 它将如何影响性能?

这是个问题

List.Where(s => s.ValidDate.Date == DateTime.Today.Year).ToList();
Run Code Online (Sandbox Code Playgroud)

这是我的解决方案.我介绍了变量yr来存储年份.

int yr = DateTime.Now.Year;
List.Where(s => s.ValidDate.Year == yr).ToList();
Run Code Online (Sandbox Code Playgroud)

这是答案的评论

kni*_*ttl 14

首先,这两个解决方案在功能上并不相同(如果您修复了将日期与int(.Date == .Today.Year)进行比较):

  • 第一个片段重新评估DateTime.Today.Year列表的每个值,当迭代期间当前年份发生变化时,可以给出不同的结果

  • 第二个代码段存储当前年份并重新使用该年份,因此结果列表中的所有项目都将具有相同的年份.(我个人采取这种方法,因为我想确保结果是理智的).

引入闭包是因为lambda从其外部作用域访问变量,它关闭了值yr.C#编译将生成一个新类,其中包含一个字段yr.所有引用yr都将替换为新字段,原始文件yr甚至不会存在于已编译的代码中

我怀疑通过引入一个闭包会有性能损失.如果有的话,使用闭包的代码会更快,因为它不必DateTime为每个列表项创建新实例,然后取消引用两个属性.它只需要访问编译器生成的闭包类的字段,该闭包类保存当前年份的int值.(任何想要比较生成的IL代码或配置两个片段的人?:))


Dim*_*rov 6

除了knittl的答案,我想尝试和测量有和没有闭合的性能,这是我的测试看起来像:

internal class SomeData {
    public DateTime ValidDate { get; set; }
    // other data ...
}

class Program {
    static void Main(string[] args) {
        var stopWatch = new Stopwatch();

        // Test with closure
        IEnumerable<SomeData> data1 = CreateTestData(100000);
        stopWatch.Start();
        int yr = DateTime.Now.Year;
        List<SomeData> results1 = data1.Where(x => x.ValidDate.Year == yr).ToList();
        stopWatch.Stop();
        Console.WriteLine("With a closure - {0} ms", stopWatch.Elapsed.Milliseconds);
        // ### Output on my machine (consistently): With a closure - 16 ms

        stopWatch.Reset();

        // Test without a closure            
        IEnumerable<SomeData> data2 = CreateTestData(100000);
        stopWatch.Start();
        List<SomeData> results2 = data2.Where(x => x.ValidDate.Year == DateTime.Today.Year).ToList();
        stopWatch.Stop();
        Console.WriteLine("Without a closure - {0} ms", stopWatch.Elapsed.Milliseconds);
        // ### Output on my machine: Without a closure - 33 ms
    }

    private static IEnumerable<SomeData> CreateTestData(int numberOfItems) {
        var dt = DateTime.Today;
        for (int i = 0; i < numberOfItems; i++) {
            yield return new SomeData {ValidDate = dt};
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我测试的底线 - 正如我所预期的那样,带闭合的版本要快得多.