Anahtar Hızı ile Karşılaştırması


112

Switch ifadeleri, derleyici optimizasyonları nedeniyle genellikle eşdeğer if-else-if ifadelerinden (örneğin bu makalede açıklanan ) daha hızlıdır .

Bu optimizasyon aslında nasıl çalışıyor? İyi bir açıklaması olan var mı?



Yanıtlar:


185

Derleyici, uygun olan yerlerde atlama tabloları oluşturabilir. Örneğin, üretilen koda bakmak için yansıtıcıyı kullandığınızda, dizelerdeki devasa anahtarlar için derleyicinin bunları göndermek için bir karma tablo kullanan bir kod üreteceğini göreceksiniz. Karma tablo, dizeleri anahtar olarak ve casekodlara değer olarak delegeler kullanır .

Bu, çok sayıda zincirleme iftestten daha asimptotik daha iyi çalışma süresine sahiptir ve aslında nispeten az sayıda dizge için bile daha hızlıdır.


6
İyi cevap, hash tablosu hakkında ilginç.
BobbyShaftoe

4
Ayrıca bazı durumlarda ağaç karşılaştırmalarına da dönüşürler. Muhakeme biraz karmaşıktır, ancak temelde modern cpu atlama hedef tamponlarını kısırlaştırarak tabloya indirgenir ve böylelikle dal öngörücüsünü ortadan kaldırır. Anahtarlar için kodlayıcı üzerine bir GCC konferansındaki bir makaleyi belli belirsiz hatırlıyorum.
olliej

Bunun anlamı: switch (a) case "x": case "y": case "z": // bir şey bozulur; } şundan daha hızlıdır: if (a == "x" || a == "b" || a == "c") // bir şey doğru mu?
yazanpro

burada başka olursa iç içe geçmişiz yok, sadece VEYA öyleyse ne düşünüyorsunuz?
yazanpro

@yazanpro Eski derleyicilerde potansiyel olarak evet (ancak vaka sayısının bir fark yaratmayabilecek kadar az olduğuna dikkat edin!). Modern derleyiciler yine de çok daha fazla kod analizi yapar. Sonuç olarak, bu iki kod parçacığının eşdeğer olduğunu anlayabilir ve aynı optimizasyonları uygulayabilirler. Ama bu benim açımdan saf bir spekülasyon, herhangi bir derleyicinin bunu gerçekten yapıp yapmadığını bilmiyorum.
Konrad Rudolph

15

Bu, tipik olarak if..else if ..bir kişi tarafından önemsiz bir şekilde switch ifadesine dönüştürülebilen bir diziyle karşılaşan herhangi bir modern derleyici gibi hafif bir basitleştirmedir , derleyici de yapacaktır. Ancak daha fazla eğlence eklemek için derleyici sözdizimi ile kısıtlanmamıştır, bu nedenle dahili olarak aralıkların, tek hedeflerin vb. Karışımına sahip "anahtar" benzeri ifadeler üretebilir - ve bunu hem switch hem de if için yapabilirler (ve yaparlar). .else ifadeleri.

Her neyse, Konrad'ın cevabının bir uzantısı, derleyicinin bir atlama tablosu oluşturabileceğidir, ancak bu mutlaka garanti edilmez (veya istenmez). Çeşitli nedenlerden dolayı atlama tabloları, modern işlemcilerdeki şube tahmin edicilerine kötü şeyler yapar ve tablolar davranışları önbelleğe almak için kötü şeyler yapar, örn.

switch(a) { case 0: ...; break; case 1: ...; break; }

Bir derleyici gerçekten bunun için bir atlama tablosu oluşturduysa if..else if.., atlama tablosunun dallanma tahminini bozması nedeniyle alternatif stil kodunun daha yavaş olması muhtemeldir .


4

Maç yok istatistikleri iyi olmayabilir.

Kaynağı gerçekten indirirseniz, hem if hem de anahtar durumunda 21 eşleşme yok değerleri olarak bilinir. Bir derleyici, hangi ifadenin her zaman çalıştırılması gerektiğini bilerek soyutlama yapabilmelidir ve bir CPU, tahmini doğru şekilde dallara ayırabilmelidir.

Daha ilginç olan durum, bence her vakanın bozulmamasıdır, ancak deneyin kapsamı bu olmayabilir.


4

Switch / case deyimleri genellikle daha hızlı 1 düzey derinlikte olabilir, ancak 2 veya daha fazlasına girmeye başladığınızda, switch / case deyimleri, iç içe geçen if / else deyimlerinin 2-3 katını almaya başlar.

Bu makale, bu tür ifadeler iç içe geçtiğinde hız farklılıklarını vurgulayan bazı hız karşılaştırmalarına sahiptir .

Örneğin, testlerine göre aşağıdaki gibi örnek kod:

if (x % 3 == 0)
            if (y % 3 == 0)
                total += 3;
            else if (y % 3 == 1)
                total += 2;
            else if (y % 3 == 2)
                total += 1;
            else
                total += 0;
        else if (x % 3 == 1)
            if (y % 3 == 0)
                total += 3;
            else if (y % 3 == 1)
                total += 2;
            else if (y % 3 == 2)
                total += 1;
            else
                total += 0;
        else if (x % 3 == 2)
            if (y % 3 == 0)
                total += 3;
            else if (y % 3 == 1)
                total += 2;
            else if (y % 3 == 2)
                total += 1;
            else
                total += 0;
        else
            if (y % 3 == 0)
                total += 3;
            else if (y % 3 == 1)
                total += 2;
            else if (y % 3 == 2)
                total += 1;
            else
                total += 0;

eşdeğer switch / case ifadesinin çalışması için geçen sürenin yarısında bitti :

switch (x % 3)
    {
        case 0:
            switch (y % 3)
            {
                case 0: total += 3;
                    break;
                case 1: total += 2;
                    break;
                case 2: total += 1;
                    break;
                default: total += 0;
                    break;
            }
            break;
        case 1:
            switch (y % 3)
            {
                case 0: total += 3;
                    break;
                case 1: total += 2;
                    break;
                case 2: total += 1;
                    break;
                default: total += 0;
                    break;
            }
            break;
    case 2:
            switch (y % 3)
            {
                case 0: total += 3;
                    break;
                case 1: total += 2;
                    break;
                case 2: total += 1;
                    break;
                default: total += 0;
                    break;
            }
            break;
    default:
        switch (y % 3)
        {
            case 0: total += 3;
                break;
            case 1: total += 2;
                break;
            case 2: total += 1;
                break;
            default: total += 0;
                break;
        }
        break;
    }

Evet, ilkel bir örnek, ama asıl noktayı gösteriyor.

Dolayısıyla, yalnızca bir düzey derinliğinde olan basit türler için anahtar / durum kullanımı olabilir, ancak daha karmaşık karşılaştırmalar ve birden çok iç içe geçmiş düzey için klasik if / else yapılarını kullanın.


-1: 1. Makale, Dal Tahminini tamamen göz ardı etti, 2. Algoritmalar tam olarak aynı değil (bağlantıdaki tek eğer-değilse zaten daha optimize edilmiş) ve 3. Bulunan farklar o kadar küçük ki hiçbir şey mazeret göstermiyor uygun, temiz kod kullanımı (anahtar ile aynı eğer-değilse yapısı arasında 10.000.000
aramada

Bu örnek, anahtar bloğunun sahip olduğu az sayıda durum nedeniyle optimize edilmeyecektir. Genellikle 5-6 öğeden sonra bir atlama tablosu oluşturur.
antiduh

0

Eğer fazla durumunun tek avantajı, ilk durumun ortaya çıkma sıklığında gözle görülür bir artış olduğu zamandır.

Eşiğin tam olarak nerede olduğundan emin değilim, ancak ilk "neredeyse her zaman" ilk testi geçmediği sürece büyük / küçük harf sözdizimini kullanıyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.