2010-06-16 15 views
9

Kendimi eski bir 3.5 çerçeve eski kodundan geçiyordum ve bir bütünün olduğu bazı noktalar buldum. senkronize bir şekilde güncellenmesi gereken listeler ve sözlükler grubu. Bu süreci, yeni özel sınıfların özel konteyner sınıflarına dönüştürerek hem kullanması hem de anlaması için son derece kolay hale getirebileceğimi belirledim. Ancak, bu yeni konteyner sınıflarının içeriğini belirli bir iç özellik tarafından organize edilmeyle ilgili kaygılarımın olduğu bazı noktalar var. Örneğin, bir sınıfın ID numarası özelliğine göre sıralama. Kap sınıfları olarak Listenin Yararlı Olduğu Açıklama <T> .Sort() versus.OrderBy() özel bir kapsayıcı sınıfının bir üyesi için

öncelikle genel bir listesi nesnenin etrafında dayanır, ilk içgüdüsel IComparable iç sınıfları yazmak ve özelliklerini karşılaştırır CompareTo yöntem yazmak amaçlanmıştır. Bu şekilde, sıralamayı çağırmak istediğimde items.Sort()'u arayabilirim.

Ancak, bunun yerine items = items.OrderBy(Func) kullanma konusunda yerine düşünüyordum. Bu şekilde, başka bir mülke göre sıralama yapmam gerekirse daha esnektir. Okunabilirlik için kullanılan özellik, IComparable koduna bakmak yerine sıralamayla listeleneceğinden dolayı okunabilirlik daha iyidir. Genel uygulama sonuç olarak daha temiz hissettirir.

Ben prematüre veya mikro optimizasyonu için umurumda değil, ama tutarlılık gibi. Uygun olduğu kadar çok vaka için bir tür uygulama yapmanın en iyi yolunu buluyorum ve gerektiğinde farklı uygulamalar kullanıyorum. Kodumu List.Sort kullanmak yerine LINQ OrderBy kullanmak için buna değer mi? Bu özel kaplar için IComparable uygulamasıyla uğraşmak daha iyi bir uygulama mı? Kararın tartılacağı yollardan herhangi biri tarafından sunulan önemli mekanik avantajlar var mı? Yoksa onların son işlevselliği, sadece kodlayıcının tercih ettiği noktaya eşdeğer midir? Burada

cevap

18

önemli nokta List<T>.Sort() yerde sıralamayı yapmasıdır. Listeniz harici koda maruz kalıyorsa, her zaman bu kodun aynı nesneyi temsil edecektir. Bu liste, bir alan içerisinde kapsayıcı sınıfın dışında bir kodla tutulursa önemlidir. OrderBy() ile sıralama yapıyorsanız, her seferinde önceki items'u değiştirerek yeni bir numaralandırma alırsınız. Önceden saklanmış herhangi bir liste, sınıfınızın mevcut durumunu temsil etmeyecektir.

düşünüldüğünde performansı, OrderBy öğeleri sıralamak için tüm listesi üzerinden yineleme gerekecektir. Ardından bu numaralandırma listesinden yeni bir liste oluşturmak için listeyi ikinci kez yinelemek üzere ToList()'u arayacaksınız. Ayrıca, bir numaralandırma olduğu için, Liste, her öğe ona sığana kadar boyutunu artırarak ikiye katlama algoritmasını kullanır. Büyük bir liste halinde, bu oldukça az sayıda tahsis ve hafıza kopyalama olabilir. Performansın List<T>.Sort()'dan daha kötü olmasını beklerim.

Düzenleme: Küçük kriter:

internal class Program { 

    private static List<int> CreateList(int size) { 

     // use the same seed so that every list has the same elements 
     Random random = new Random(589134554); 

     List<int> list = new List<int>(size); 
     for (int i = 0; i < size; ++i) 
      list.Add(random.Next()); 
     return list; 
    } 

    private static void Benchmark(int size, bool output = true) { 
     List<int> list1 = CreateList(size); 
     List<int> list2 = CreateList(size); 

     Stopwatch stopwatch = Stopwatch.StartNew(); 
     list1.Sort(); 
     stopwatch.Stop(); 
     double elapsedSort = stopwatch.Elapsed.TotalMilliseconds; 
     if (output) 
      Console.WriteLine("List({0}).Sort(): {1}ms (100%)", size, elapsedSort); 

     stopwatch.Restart(); 
     list2.OrderBy(i => i).ToList(); 
     stopwatch.Stop(); 
     double elapsedOrderBy = stopwatch.Elapsed.TotalMilliseconds; 
     if (output) 
      Console.WriteLine("List({0}).OrderBy(): {1}ms ({2:.00%})", size, elapsedOrderBy, elapsedOrderBy/elapsedSort); 

    } 

    internal static void Main() { 

     // ensure linq library is loaded and initialized 
     Benchmark(1000, false); 

     Benchmark(10); 
     Benchmark(100); 
     Benchmark(1000); 
     Benchmark(10000); 
     Benchmark(100000); 
     Benchmark(1000000); 

     Console.ReadKey(); 
    } 
} 

Çıkış (List.Sort için normalize): Bahsettiğiniz beri

sırala
List(10).Sort(): 0,0025ms (100%) 
List(10).OrderBy(): 0,0157ms (628,00%) 
List(100).Sort(): 0,0068ms (100%) 
List(100).OrderBy(): 0,0294ms (432,35%) 
List(1000).Sort(): 0,0758ms (100%) 
List(1000).OrderBy(): 0,3107ms (409,89%) 
List(10000).Sort(): 0,8969ms (100%) 
List(10000).OrderBy(): 4,0751ms (454,35%) 
List(100000).Sort(): 10,8541ms (100%) 
List(100000).OrderBy(): 50,3497ms (463,88%) 
List(1000000).Sort(): 124,1001ms (100%) 
List(1000000).OrderBy(): 705,0707ms (568,15%) 
+0

Ölçütlerinizin gösterdiği birim ... birimleriyle ilgilidir.Bunun gibi oranlarda, 3 OrderBy kullanmam için 3 sırayla bile sıkıştırabilirim ve sadece bir OrderBy kullanmış olmamadan daha iyi bir performans elde ettim! Sırala() –

+0

Hesaplarınızdan yola çıkarak hızlı bir takip, bu da demek oluyor ki 'items.First()' 'item [0]' dan çok daha yavaştır? –

+0

Hayır, 'First()', IList 'uygulamaları için optimize edilmiştir ve [0]' listesini döndürecektir. Performansın aynı olmasını bekliyorum. Sayımı doğrudan kullanarak bile olsa, hala yinelenmesi gereken tek bir öğe olur, bu yüzden muhtemelen bir mikro optimizasyon olacaktır. –

4

Julien dediği gibi,() muhtemelen ancak daha hızlı olacaktır daha iyi okunabilirliği ve OrderBy() esnekliği, sen de (Mülkiyet Eğer karşılaştırılabilir üzerinde sıralama temel istediğiniz en az ise)

, senin Sıralama() yöntemi ile elde edebilirsiniz
items = items.OrderBy(x => x.Name).ToList(); 
items.Sort((x,y) => x.Name.CompareTo(y.Name)); // If x.Name is never null 
items.Sort((x,y) => String.Compare(x.Name, y.Name)); // null safe 
+0

Bu günlerden biri, "IComparable'a güvenmek yerine Sıralama işlevini belirtebilirim" gibi ekstra küçük şeyleri unutmayı bırakacağım. Bu harika, çünkü bu, bazı sınıfları gerçekten bu duyguya sahip olmadıkları zaman "karşılaştırılabilir" olarak belirlemekten kaçınmamı sağlıyor, sadece belirli durumlarda sıralanmaları gerekiyor. Başarımı sağlamak için cevabınızı Julien'in verileriyle birleştirdim. Çok teşekkürler! –

+0

IComparer 'u IComparable'a tercih ediyorum. Bu şekilde sıralama algoritmalarının farklı kapsüllülerinden geçebilirsiniz. –

İlgili konular