Các câu lệnh switch thường nhanh hơn các câu lệnh if-else-if tương đương (ví dụ như được mô tả trong bài viết này ) do tối ưu hóa trình biên dịch.
Làm thế nào để tối ưu hóa này thực sự hoạt động? Có ai có một lời giải thích tốt?
Các câu lệnh switch thường nhanh hơn các câu lệnh if-else-if tương đương (ví dụ như được mô tả trong bài viết này ) do tối ưu hóa trình biên dịch.
Làm thế nào để tối ưu hóa này thực sự hoạt động? Có ai có một lời giải thích tốt?
Câu trả lời:
Trình biên dịch có thể xây dựng bảng nhảy nếu có. Ví dụ: khi bạn sử dụng phản xạ để xem mã được tạo, bạn sẽ thấy rằng đối với các công tắc lớn trên chuỗi, trình biên dịch sẽ thực sự tạo ra mã sử dụng bảng băm để gửi chúng. Bảng băm sử dụng các chuỗi làm khóa và ủy quyền cho các case
mã dưới dạng giá trị.
Điều này có thời gian chạy tiệm cận tốt hơn so với nhiều if
bài kiểm tra theo chuỗi và thực sự nhanh hơn ngay cả đối với tương đối ít chuỗi.
Đây là một sự đơn giản hóa nhỏ vì thông thường bất kỳ trình biên dịch hiện đại nào gặp phải một if..else if ..
trình tự có thể được một người chuyển đổi thành câu lệnh switch một cách đáng kể, trình biên dịch cũng sẽ như vậy. Nhưng chỉ để thêm phần thú vị, trình biên dịch không bị hạn chế bởi cú pháp vì vậy có thể tạo "switch" như các câu lệnh bên trong có sự kết hợp của phạm vi, mục tiêu đơn lẻ, v.v. - và chúng có thể (và làm) làm điều này cho cả switch và if. .else câu lệnh.
Anyhoo, một phần mở rộng cho câu trả lời của Konrad là trình biên dịch có thể tạo bảng nhảy, nhưng điều đó không nhất thiết phải đảm bảo (cũng không mong muốn). Vì nhiều lý do khác nhau, các bảng nhảy có tác dụng xấu đối với các yếu tố dự đoán nhánh trên các bộ xử lý hiện đại và bản thân các bảng này thực hiện các tác vụ xấu đối với hành vi của bộ đệm, ví dụ:
switch(a) { case 0: ...; break; case 1: ...; break; }
Nếu một trình biên dịch thực sự tạo một bảng nhảy cho điều này, thì if..else if..
mã kiểu thay thế sẽ chậm hơn vì bảng nhảy đánh bại dự đoán nhánh.
Số liệu thống kê không có trận đấu có thể không tốt.
Nếu bạn thực sự tải xuống nguồn, không có giá trị khớp nào được biết là 21, trong cả trường hợp if và switch. Một trình biên dịch phải có thể trừu tượng hóa, biết câu lệnh nào nên được chạy mọi lúc và CPU phải có thể phân nhánh dự đoán đúng cách.
Theo tôi, trường hợp thú vị hơn là khi không phải trường hợp nào cũng vỡ, nhưng đó có thể không phải là phạm vi của thử nghiệm.
Các câu lệnh switch / case thường có thể nhanh hơn sâu 1 cấp, nhưng khi bạn bắt đầu vào 2 hoặc nhiều hơn, các câu lệnh switch / case sẽ bắt đầu mất thời gian gấp 2-3 lần các câu lệnh if / else lồng nhau.
Bài viết này có một số so sánh tốc độ nêu bật sự khác biệt về tốc độ khi các câu lệnh như vậy được lồng vào nhau.
Ví dụ: theo thử nghiệm của họ, mã mẫu như sau:
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;
đã hoàn thành trong một nửa thời gian mà câu lệnh switch / case tương đương đã chạy:
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;
}
Vâng, đó là một ví dụ thô sơ, nhưng nó minh họa quan điểm.
Vì vậy, một kết luận có thể là sử dụng switch / case cho các kiểu đơn giản chỉ sâu một cấp, nhưng đối với các so sánh phức tạp hơn và nhiều cấp lồng nhau, hãy sử dụng cấu trúc if / else cổ điển?