2009-07-31 37 views
14

Hi giả những 2 phương pháp:C# Danh sách <T> vs IEnumerable <T> hiệu suất câu hỏi

private List<IObjectProvider> GetProviderForType(Type type) 
     { 
      List<IObjectProvider> returnValue = new List<IObjectProvider>(); 

      foreach (KeyValuePair<Type, IObjectProvider> provider in _objectProviders) 
      { 
       if ((provider.Key.IsAssignableFrom(type) || 
        type.IsAssignableFrom(provider.Key)) && 
        provider.Value.SupportsType(type)) 
       { 
        returnValue.Add(provider.Value); 
       } 
      } 
      return returnValue; 
     } 

private IEnumerable<IObjectProvider> GetProviderForType1(Type type) 
     { 
      foreach (KeyValuePair<Type, IObjectProvider> provider in _objectProviders) 
       if ((provider.Key.IsAssignableFrom(type) || 
        type.IsAssignableFrom(provider.Key)) && 
        provider.Value.SupportsType(type)) 

        yield return provider.Value;    
     } 

Cái nào là nhanh hơn? Khi tôi nhìn vào phương pháp đầu tiên, tôi thấy rằng bộ nhớ được phân bổ cho Danh sách, theo ý kiến ​​của tôi thì nó không cần thiết. Phương thức IEnumerable có vẻ nhanh hơn với tôi.

Ví dụ, giả sử bạn gọi

int a = GetProviderForType(myType).Count; 
int b = GetProviderForType1(myType).Count(); 

Bây giờ, một vấn đề khác là, có một sự khác biệt về hiệu năng giữa những 2 ở trên?

Bạn nghĩ sao?

+13

Câu trả lời cho tất cả "nhanh hơn?" câu hỏi là như nhau: Hãy thử cả hai cách. Lấy ra một đồng hồ bấm giờ. Sau đó, bạn sẽ biết. –

Trả lời

30

Trong trường hợp cụ thể này, sử dụng biểu mẫu IEnumerable<T> sẽ hiệu quả hơn vì bạn chỉ chỉ cần biết số lượng. Không có điểm lưu trữ dữ liệu, thay đổi kích thước bộ đệm, v.v. nếu bạn không cần.

Nếu bạn cần sử dụng lại kết quả vì bất kỳ lý do nào, biểu mẫu List<T> sẽ hiệu quả hơn.

Lưu ý rằng cả hai phương pháp Count() khuyến nông và Count bất động sản sẽ có hiệu quả cho List<T> như việc thực hiện các Count() kiểm tra xem nếu chuỗi mục tiêu thực hiện ICollection<T> và sử dụng Count tài sản nếu như vậy.

Một tùy chọn khác mà nên thậm chí hơn hiệu quả (mặc dù chỉ mới) sẽ được gọi là tình trạng quá tải của Count mà phải mất một đại biểu:

private int GetProviderCount(Type type) 
{ 
    return _objectProviders.Count(provider => 
     (provider.Key.IsAssignableFrom(type) 
     || type.IsAssignableFrom(provider.Key)) 
     && provider.Value.SupportsType(type)); 
} 

Điều đó sẽ tránh được cấp thêm indirections phát sinh do việc WhereSelect điều khoản.

(Như Marc nói, cho một lượng nhỏ dữ liệu sự khác biệt hiệu suất có thể sẽ là không đáng kể anyway.)

+0

Tôi nghĩ bạn nên quay trở lại một int trong trường hợp này –

+0

Doh - tất nhiên. Cố định, cảm ơn :) –

+2

Tất cả các câu trả lời của bạn đã thực sự giúp tôi, nhưng tôi nghĩ rằng điều này có tất cả mọi thứ được đề cập, vì vậy tôi chấp nhận nó. Cảm ơn bạn! –

4

Câu trả lời chính xác cho các câu hỏi như thế này có thể khác nhau tùy thuộc vào nhiều yếu tố và có thể thay đổi thêm khi CLR phát triển. Cách duy nhất để chắc chắn là đo lường - và lưu ý rằng nếu sự khác biệt nhỏ so với hoạt động này sẽ xuất hiện, thì bạn nên chọn cách dễ đọc nhất, có thể duy trì được bằng văn bản.

Và lưu ý rằng, bạn cũng có thể muốn thử:

private IEnumerable<IObjectProvider> GetProviderForType1(Type type) 
{ 
    return _objectProviders.Where(provider => 
        provider.Key.IsAssignableFrom(type) || 
        type.IsAssignableFrom(provider.Key)) && 
        provider.Value.SupportsType(type)) 
          .Select(p => p.Value); 
} 

Bạn cũng có thể cung cấp cho mình rất nhiều tính linh hoạt bằng cách quay IEnumerable<T> và sau đó sử dụng phương pháp ToList mở rộng nếu bạn muốn "ảnh chụp" các kết quả vào danh sách. Điều này sẽ tránh đánh giá lặp lại mã để tạo danh sách, nếu bạn cần kiểm tra nó nhiều lần.

4

Một phần quan trọng của câu hỏi này là "lớn như thế nào là dữ liệu"? Có bao nhiêu hàng ...

Đối với một lượng nhỏ dữ liệu, danh sách là tốt - sẽ mất thời gian không đáng kể để phân bổ danh sách đủ lớn và không thay đổi kích thước nhiều lần (không, nếu bạn biết để được trước).

Tuy nhiên, điều này không mở rộng đến khối lượng dữ liệu khổng lồ; có vẻ như nhà cung cấp của bạn không hỗ trợ hàng nghìn giao diện, vì vậy tôi sẽ không nói rằng đó là cần thiết để chuyển sang mô hình này - nhưng nó sẽ không làm tổn thương rất nhiều.

Tất nhiên, bạn có thể sử dụng LINQ, quá:

return from provider in _objectProviders 
     where provider.Key.IsAssignableFrom(type) ... 
     select provider.Value; 

Đây cũng là cách tiếp cận yield hoãn lại dưới tấm chăn ...

2

Sự khác biệt chính giữa IEnumerable và IList:

IEnumerable: Thực hiện MoveNext, Đặt lại, Nhận phương pháp hiện tại và trả về một loại trình đếm số để lặp lại Thông qua hồ sơ.

IList: Hiển thị giao diện IEnumerable cũng như tập hợp các đối tượng không chung chung có thể truy cập qua chỉ mục để IEnumerable + ICollection (Thao tác dữ liệu) và thêm, loại bỏ, Chèn (tại chỉ mục cụ thể) là phương pháp hữu ích được thực hiện bởi IList.

Sau khi xem mã của bạn, tôi có thể đếm được danh sách trả về hiệu quả hơn nếu bạn muốn thực hiện thao tác với dữ liệu và nếu bạn chỉ muốn thay đổi dữ liệu thì IEnumerable là thích hợp hơn.

+1

Sai. IEnumerable chỉ có một phương pháp. Trả về một trình vòng lặp có hiệu quả hơn đáng kể khi xây dựng một danh sách. – SLaks

+1

Một khả năng khác là trả về một kiểu thực hiện 'ICollection' (không chung chung!) Trong kiểu chỉ đọc cũng như 'IEnumerable ' và có thể là' ICollection '. Nếu một lớp thực hiện 'IEnumerable ' cũng thực hiện 'ICollection' hoặc' ICollection ', phương thức mở rộng' Count' cho 'IEnumerable ' sẽ sử dụng phương thức 'Đếm' của một trong các giao diện đó. Nếu không, nó sẽ phải liệt kê tất cả các mục để đếm. Lưu ý rằng dạng không chung chung có ích hơn một chút cho mục đích này vì ... – supercat

+1

... một 'IEnumeration ' có thể được sử dụng như một 'IEnumeration ', nhưng không thể sử dụng 'ICollection ' làm một ICollection '. Nếu một thường trình mong đợi một 'IEnumeration ' được đưa ra một cá thể lớp thực hiện 'ICollection ' nhưng không phải là 'ICollection' không chung chung, nó sẽ không có cách nào để biết rằng bộ sưu tập sẽ được đưa vào' ICollection ' lấy số lượng. Tuy nhiên, nếu lớp thực thi 'ICollection' không chung chung, mã mà hy vọng một 'IEnumerable ' sẽ không gặp khó khăn khi tìm ra điều đó. – supercat

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