Pernyataan switch biasanya lebih cepat daripada pernyataan if-else-if yang setara (seperti yang dijelaskan di artikel ini ) karena pengoptimalan compiler.
Bagaimana sebenarnya pengoptimalan ini bekerja? Apakah ada yang punya penjelasan yang bagus?
Pernyataan switch biasanya lebih cepat daripada pernyataan if-else-if yang setara (seperti yang dijelaskan di artikel ini ) karena pengoptimalan compiler.
Bagaimana sebenarnya pengoptimalan ini bekerja? Apakah ada yang punya penjelasan yang bagus?
Jawaban:
Kompiler dapat membuat tabel lompat jika memungkinkan. Misalnya, ketika Anda menggunakan reflektor untuk melihat kode yang dihasilkan, Anda akan melihat bahwa untuk sakelar besar pada string, kompilator akan benar-benar menghasilkan kode yang menggunakan tabel hash untuk mengirimkannya. Tabel hash menggunakan string sebagai kunci dan mendelegasikan case
kode sebagai nilai.
Ini memiliki waktu proses asimtotik yang lebih baik daripada banyak if
pengujian berantai dan sebenarnya lebih cepat bahkan untuk string yang relatif sedikit.
Ini adalah sedikit penyederhanaan seperti biasanya setiap kompiler modern yang menemukan if..else if ..
urutan yang dapat dengan mudah diubah menjadi pernyataan switch oleh seseorang, kompiler juga akan melakukannya. Tetapi hanya untuk menambah kesenangan tambahan, kompilator tidak dibatasi oleh sintaks sehingga dapat menghasilkan pernyataan seperti "switch" secara internal yang memiliki campuran rentang, target tunggal, dll - dan mereka dapat (dan melakukan) melakukan ini untuk kedua switch dan if. pernyataan .else.
Anyhoo, perluasan dari jawaban Konrad adalah bahwa kompilator dapat menghasilkan tabel lompat, tetapi itu belum tentu dijamin (atau diinginkan). Untuk berbagai alasan, tabel lompat melakukan hal buruk pada prediktor cabang pada prosesor modern, dan tabel itu sendiri melakukan hal buruk pada perilaku cache, misalnya.
switch(a) { case 0: ...; break; case 1: ...; break; }
Jika kompilator benar-benar membuat tabel lompat untuk ini, kemungkinan akan lebih lambat daripada if..else if..
kode gaya alternatif karena tabel lompat mengalahkan prediksi cabang.
Statistik tidak ada pertandingan mungkin tidak bagus.
Jika Anda benar-benar mengunduh sumber, nilai tidak ada kecocokan diketahui 21, baik dalam kasus if dan switch. Kompilator harus dapat mengabstraksi, mengetahui pernyataan mana yang harus dijalankan setiap saat, dan CPU harus dapat memprediksi cabang dengan benar.
Kasus yang lebih menarik adalah ketika tidak setiap kasus rusak, menurut pendapat saya, tetapi itu mungkin bukan cakupan eksperimen.
Pernyataan sakelar / kasus mungkin biasanya lebih cepat dalam 1 tingkat, tetapi ketika Anda mulai masuk ke 2 atau lebih, pernyataan sakelar / kasus mulai memakan waktu 2-3 kali lebih lama dari pernyataan if / else bersarang.
Artikel ini memiliki beberapa perbandingan kecepatan yang menyoroti perbedaan kecepatan saat pernyataan semacam itu bersarang.
Misalnya, menurut pengujian mereka, contoh kode seperti berikut:
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;
selesai setengah dari waktu yang diperlukan untuk menjalankan pernyataan 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;
}
Ya, itu contoh yang belum sempurna, tetapi itu menggambarkan maksudnya.
Jadi kesimpulannya mungkin menggunakan switch / case untuk tipe sederhana yang hanya sedalam satu level, tetapi untuk perbandingan yang lebih kompleks dan beberapa level bersarang, gunakan konstruksi if / else klasik?