ถ้าเทียบกับ Switch Speed


112

โดยทั่วไปคำสั่ง Switch จะเร็วกว่าคำสั่ง if-else-if ที่เทียบเท่า (เช่นอธิบายไว้ในบทความนี้ ) เนื่องจากการปรับแต่งคอมไพลเลอร์

การเพิ่มประสิทธิภาพนี้ทำงานอย่างไร ใครมีคำอธิบายดีๆ



คำตอบที่ดีที่เป็นไปได้: dotnetperls.com/if-switch-performance
Babak

คำตอบ:


185

คอมไพเลอร์สามารถสร้างตารางกระโดดได้หากมี ตัวอย่างเช่นเมื่อคุณใช้ตัวสะท้อนแสงเพื่อดูโค้ดที่สร้างขึ้นคุณจะเห็นว่าสำหรับสวิตช์ขนาดใหญ่บนสตริงคอมไพเลอร์จะสร้างโค้ดที่ใช้ตารางแฮชเพื่อส่งสิ่งเหล่านี้ ตารางแฮชใช้สตริงเป็นคีย์และมอบหมายให้caseโค้ดเป็นค่า

สิ่งนี้มีรันไทม์ที่ไม่แสดงอาการดีกว่าifการทดสอบแบบล่ามโซ่จำนวนมากและเร็วกว่าแม้ว่าจะมีสตริงที่ค่อนข้างน้อยก็ตาม


6
คำตอบที่ดีน่าสนใจเกี่ยวกับตารางแฮช
BobbyShaftoe

4
นอกจากนี้ยังแปลงเป็นการเปรียบเทียบต้นไม้ในบางกรณี การให้เหตุผลค่อนข้างซับซ้อน แต่โดยพื้นฐานแล้วจะลดลงไปที่ตารางการทำหมันบัฟเฟอร์เป้าหมายการกระโดดของซีพียูที่ทันสมัยและลบตัวทำนายสาขาออกไป ฉันจำกระดาษในการประชุม GCC เกี่ยวกับ codegen สำหรับสวิตช์ได้อย่างคลุมเครือ
olliej

นั่นหมายความว่า: switch (a) case "x": case "y": case "z": // something break; } เร็วกว่า: if (a == "x" || a == "b" || a == "c") // อะไรนะ?
yazanpro

ที่นี่เราไม่มีซ้อนกันถ้าอย่างอื่นเท่านั้นหรือคุณคิดอย่างไร?
yazanpro

@yazanpro ในคอมไพเลอร์เก่าอาจใช่ (แต่โปรดทราบว่าจำนวนเคสน้อยมากจนอาจไม่สร้างความแตกต่าง!) คอมไพเลอร์สมัยใหม่ทำการวิเคราะห์โค้ดได้มากขึ้น ด้วยเหตุนี้พวกเขาอาจคิดว่าข้อมูลโค้ดทั้งสองนี้มีค่าเท่ากันและใช้การเพิ่มประสิทธิภาพเดียวกัน แต่นี่เป็นการคาดเดาอย่างแท้จริงในส่วนของฉันฉันไม่รู้ว่าคอมไพเลอร์ใดทำอย่างนั้นจริง
Konrad Rudolph

15

นี่เป็นการทำให้ง่ายขึ้นเล็กน้อยตามปกติแล้วคอมไพเลอร์สมัยใหม่ใด ๆ ที่พบif..else if ..ลำดับที่สามารถแปลงเป็นคำสั่งสวิตช์โดยบุคคลได้เล็กน้อยคอมไพเลอร์ก็เช่นกัน แต่เพื่อเพิ่มความสนุกเป็นพิเศษคอมไพลเลอร์ไม่ได้ถูก จำกัด ด้วยไวยากรณ์ดังนั้นจึงสามารถสร้าง "สวิตช์" เช่นเดียวกับคำสั่งภายในที่มีการผสมผสานของช่วงเป้าหมายเดียว ฯลฯ - และพวกเขาสามารถ (และทำ) ทำสิ่งนี้ได้สำหรับทั้งสวิตช์และ if .else งบ

Anyhoo ส่วนขยายของคำตอบของ Konrad คือคอมไพเลอร์อาจสร้างตารางการกระโดด แต่ก็ไม่จำเป็นต้องรับประกัน (หรือเป็นที่ต้องการ) ด้วยเหตุผลหลายประการตารางการกระโดดทำให้เกิดสิ่งที่ไม่ดีกับตัวทำนายสาขาในโปรเซสเซอร์สมัยใหม่และตารางเองก็ทำสิ่งที่ไม่ดีต่อพฤติกรรมแคชเช่น

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

หากคอมไพเลอร์สร้างตารางกระโดดสำหรับสิ่งนี้จริง ๆ ก็น่าจะช้ากว่าที่if..else if..โค้ดรูปแบบทางเลือกเนื่องจากตารางกระโดดที่เอาชนะการทำนายสาขา


4

สถิติที่ไม่ตรงกันอาจไม่ดี

หากคุณดาวน์โหลดแหล่งที่มาจริง ๆ ค่าที่ไม่ตรงกันจะเป็น 21 ทั้งในกรณี if และ switch คอมไพเลอร์ควรสามารถสรุปได้โดยรู้ว่าคำสั่งใดควรถูกเรียกใช้ตลอดเวลาและซีพียูควรจะสามารถแยกการทำนายได้อย่างถูกต้อง

กรณีที่น่าสนใจกว่าคือเมื่อไม่ใช่ทุกกรณีในความคิดของฉัน แต่นั่นอาจไม่ใช่ขอบเขตของการทดลอง


4

คำสั่ง Switch / case อาจเร็วกว่า 1 ระดับลึก แต่เมื่อคุณเริ่มเข้าสู่ 2 หรือมากกว่าคำสั่ง switch / case จะเริ่มใช้เวลา 2-3 เท่าตราบเท่าที่คำสั่ง if / else แบบซ้อนกัน

บทความนี้มีการเปรียบเทียบความเร็วบางส่วนที่เน้นความแตกต่างของความเร็วเมื่อข้อความดังกล่าวซ้อนกัน

ตัวอย่างเช่นตามการทดสอบของพวกเขาตัวอย่างโค้ดดังต่อไปนี้:

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;

เสร็จสิ้นในครึ่งเวลาที่คำสั่ง switch / case ที่เทียบเท่าใช้ในการรัน:

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

ใช่มันเป็นตัวอย่างพื้นฐาน แต่มันแสดงให้เห็นถึงประเด็น

ดังนั้นข้อสรุปอาจใช้สวิตช์ / กรณีสำหรับประเภทง่ายๆที่ลึกเพียงระดับเดียว แต่สำหรับการเปรียบเทียบที่ซับซ้อนมากขึ้นและระดับซ้อนกันหลายระดับให้ใช้การสร้าง if / else แบบคลาสสิก?


-1: 1 บทความนี้ไม่สนใจการทำนายสาขาโดยสิ้นเชิง 2. อัลกอริทึมไม่เหมือนกันทุกประการ (if-else อันเดียวในลิงก์ได้รับการเข้ารหัสให้เหมาะสมกว่าแล้ว) และ 3. ความแตกต่างที่พบมีขนาดเล็กมากจนไม่มีข้อแก้ตัว การใช้รหัสที่เหมาะสมและสะอาด (ประมาณ 4 ns ใน 10.000.000 การเรียกระหว่างสวิตช์และโครงสร้าง if-else แบบเดียวกัน)
Trojaner

ตัวอย่างนั้นจะไม่ได้รับการปรับให้เหมาะสมเนื่องจากบล็อกสวิตช์มีไม่กี่กรณี โดยปกติหลังจาก 5-6 องค์ประกอบมันจะสร้างตารางกระโดด
antiduh

0

ข้อดีอย่างเดียวของ if over case คือเมื่อมีความถี่ในการเกิดกรณีแรกเพิ่มขึ้นอย่างเห็นได้ชัด

ไม่แน่ใจว่าธรณีประตูอยู่ตรงไหน แต่ฉันใช้ case syntax เว้นแต่ว่า "เกือบตลอดเวลา" แรกจะผ่านการทดสอบครั้งแรก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.