Tuple<long,long,string>Üzerinde basit bir "arasında" arama gerçekleştiriyorum 500000 rasgele oluşturulan nesnelerin bir listesi var :
var data = new List<Tuple<long,long,string>>(500000);
...
var cnt = data.Count(t => t.Item1 <= x && t.Item2 >= x);
Rastgele dizimi oluşturduğumda ve aramamı rastgele oluşturulmuş 100 değer için çalıştırdığımda x, aramalar yaklaşık dört saniye içinde tamamlanıyor. Bununla birlikte, sıralamanın aramaya yaptığı harika harikaları bilerek, 100 aramamı çalıştırmadan önce verilerimi - önce Item1, sonra Item2ve son olarak Item3- sıralamaya karar verdim . Sıralı versiyonun şube tahmini nedeniyle biraz daha hızlı performans göstermesini bekledim: düşüncem, bir kez daha geldiğimizde Item1 == x, tüm diğer kontrollerin t.Item1 <= xdalı "kuyruk alma" olarak doğru şekilde tahmin edeceği ve kuyruk kısmını hızlandıracağıydı. arama. Çok şaşırdım, aramalar sıralı bir dizide iki kat daha uzun sürdü !
Deneylerimi çalıştırdığım sırada geçiş yapmayı denedim ve rastgele sayı üreteci için farklı tohum kullandım, ancak etki aynı oldu: sıralanmamış bir dizideki aramalar, aynı dizideki aramaların neredeyse iki katı kadar hızlı koştu, ancak sıralanmış!
Herkes bu garip etki hakkında iyi bir açıklama var mı? Testlerimin kaynak kodu şöyle; .NET 4.0 kullanıyorum.
private const int TotalCount = 500000;
private const int TotalQueries = 100;
private static long NextLong(Random r) {
var data = new byte[8];
r.NextBytes(data);
return BitConverter.ToInt64(data, 0);
}
private class TupleComparer : IComparer<Tuple<long,long,string>> {
public int Compare(Tuple<long,long,string> x, Tuple<long,long,string> y) {
var res = x.Item1.CompareTo(y.Item1);
if (res != 0) return res;
res = x.Item2.CompareTo(y.Item2);
return (res != 0) ? res : String.CompareOrdinal(x.Item3, y.Item3);
}
}
static void Test(bool doSort) {
var data = new List<Tuple<long,long,string>>(TotalCount);
var random = new Random(1000000007);
var sw = new Stopwatch();
sw.Start();
for (var i = 0 ; i != TotalCount ; i++) {
var a = NextLong(random);
var b = NextLong(random);
if (a > b) {
var tmp = a;
a = b;
b = tmp;
}
var s = string.Format("{0}-{1}", a, b);
data.Add(Tuple.Create(a, b, s));
}
sw.Stop();
if (doSort) {
data.Sort(new TupleComparer());
}
Console.WriteLine("Populated in {0}", sw.Elapsed);
sw.Reset();
var total = 0L;
sw.Start();
for (var i = 0 ; i != TotalQueries ; i++) {
var x = NextLong(random);
var cnt = data.Count(t => t.Item1 <= x && t.Item2 >= x);
total += cnt;
}
sw.Stop();
Console.WriteLine("Found {0} matches in {1} ({2})", total, sw.Elapsed, doSort ? "Sorted" : "Unsorted");
}
static void Main() {
Test(false);
Test(true);
Test(false);
Test(true);
}
Populated in 00:00:01.3176257
Found 15614281 matches in 00:00:04.2463478 (Unsorted)
Populated in 00:00:01.3345087
Found 15614281 matches in 00:00:08.5393730 (Sorted)
Populated in 00:00:01.3665681
Found 15614281 matches in 00:00:04.1796578 (Unsorted)
Populated in 00:00:01.3326378
Found 15614281 matches in 00:00:08.6027886 (Sorted)
Item1 == xtüm kontrollerin t.Item1 <= xdalın "yok alma" olarak doğru tahmin edileceği ve aramanın kuyruk kısmını hızlandıracağı noktaya geldiğiydi. Açıkçası, bu düşünce çizgisi sert gerçeklik tarafından yanlış kanıtlanmıştır :)