2014-07-12 10 views
10

Trong khi đưa ra câu trả lời cho một câu hỏi SO, tôi đã nói rằng giải pháp của tôi sẽ giới thiệu một đóng cửa trên biến vì vậy nó sẽ có hiệu suất hơi tồi tệ hơn. Vì vậy, câu hỏi của tôi là:"Đóng cửa trên biến cho hiệu suất hơi tồi tệ hơn". Làm sao?

  1. Làm thế nào sẽ có đóng cửa?
  2. Nó ảnh hưởng như thế nào đến hiệu suất?

Đây là question

List.Where(s => s.ValidDate.Date == DateTime.Today.Year).ToList(); 

Đây là solution tôi. Tôi đã giới thiệu biến số yr để lưu trữ năm.

int yr = DateTime.Now.Year; 
List.Where(s => s.ValidDate.Year == yr).ToList(); 

Dưới đây là vào những câu trả lời comments

+3

Hai đoạn mã này có ngữ nghĩa khác nhau. Nếu nó được chạy qua đêm trước năm mới và năm thay đổi giữa các hoạt động bạn sẽ nhận được kết quả khác nhau. Và cuối cùng - tôi giả sử - việc sử dụng mã đóng sẽ nhanh hơn, vì bạn không phải tạo các trường hợp 'DateTime' mới với mỗi vòng lặp lặp lại và bạn không phải truy cập hai thuộc tính bổ sung (giới thiệu một cấp độ khác của vô hướng). – knittl

+0

@knittl trong câu hỏi ban đầu đã được đề cập trong phần bình luận. Nhưng đóng cửa được giới thiệu ở đâu? – Sascha

+0

Vâng, thành thật không nên giải pháp với việc đóng cửa được nhanh hơn? (nó hoạt động khác nhau -> như 2 không tương đương). Nhưng nếu có gì thì nhanh hơn? –

Trả lời

14

Trước hết, hai giải pháp không phải là chức năng tương đương (Nếu bạn khắc phục so sánh hẹn hò với một int (.Date == .Today.Year)):

  • Đoạn đầu tiên đánh giá lại DateTime.Today.Year cho mỗi giá trị của danh sách, có thể cho kết quả khác nhau khi năm hiện tại thay đổi trong khi lặp lại

  • Đoạn mã thứ hai lưu trữ năm hiện tại và tái sử dụng, vì vậy tất cả các mục trong danh sách kết quả sẽ có cùng năm. (Cá nhân tôi có cách tiếp cận này, vì tôi muốn đảm bảo kết quả là sane).

Việc đóng cửa được giới thiệu vì lambda truy cập một biến từ phạm vi bên ngoài, nó đóng trên giá trị yr. Biên dịch C# sẽ tạo ra một lớp mới với một trường giữ yr. Tất cả các tham chiếu đến yr sẽ được thay thế bằng trường mới và yr ban đầu sẽ không còn tồn tại trong mã được biên dịch

Tôi nghi ngờ sẽ có một hình phạt hiệu suất bằng cách giới thiệu đóng. Nếu có, mã sử dụng đóng sẽ nhanh hơn, vì nó không phải tạo mới DateTime trường hợp cho mỗi mục danh sách và sau đó dereference hai thuộc tính. Nó chỉ phải truy cập vào trường của lớp đóng cửa do trình biên dịch tạo ra, giữ giá trị int của năm hiện tại. (Bất kỳ ai muốn so sánh mã IL được tạo ra hoặc cấu hình hai đoạn mã? :))

4

Đây là một phép đo thời gian ngây thơ, chỉ để bổ sung câu trả lời của knittl.

Kết quả là phiên bản đánh giá DateTime.Now mỗi lần vượt quá 10 lần chậm hơn so với mã của bạn.

Kết quả trên máy của tôi: T1: 8878 ms; T2: 589 mili giây. (Tối ưu hóa tối đa, không có trình sửa lỗi, v.v.).

class Program 
{ 
    static void Main(string[] args) 
    { 
     var things = new List<Something>(); 
     var random = new Random(111); 
     for (int i = 0; i < 100000; ++i) 
     { 
      things.Add(new Something(random.Next(2010, 2016))); 
     } 

     // to avoid measuring the JIT compilation and optimization time 
     T1(things); 
     T2(things); 

     var sw = Stopwatch.StartNew(); 
     for (int i = 0; i < 100; ++i) 
     { 
      T1(things); 
     } 
     Console.WriteLine(sw.ElapsedMilliseconds); 
     sw.Restart(); 
     for (int i = 0; i < 100; ++i) 
     { 
      T2(things); 
     } 
     Console.WriteLine(sw.ElapsedMilliseconds); 

     Console.ReadLine(); 
    } 

    private static void T1(List<Something> list) 
    { 
     var result = list.Where(x => x.ValidDate.Year == DateTime.Now.Year).ToList(); 
    } 

    private static void T2(List<Something> list) 
    { 
     var yr = DateTime.Now.Year; 
     var result = list.Where(x => x.ValidDate.Year == yr).ToList(); 
    } 
} 

class Something 
{ 
    public Something(int year) 
    { 
     this.ValidDate = new DateTime(year, 1, 1); 
    } 

    public DateTime ValidDate { get; private set; } 
} 
6

Ngoài câu trả lời knittl của tôi muốn cố gắng và đo hiệu suất có và không có một đóng cửa, đây là những gì thử nghiệm của tôi trông giống như:

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}; 
     } 
    } 
} 

Bottom line từ thử nghiệm của tôi - như tôi mong đợi phiên bản có đóng cửa nhanh hơn đáng kể.

Các vấn đề liên quan