Điều quan trọng là không nhầm lẫn giữa câu lệnh chuyển đổi C # với hướng dẫn chuyển đổi CIL.
Công tắc CIL là một bảng nhảy, yêu cầu một chỉ mục thành một tập hợp các địa chỉ nhảy.
Điều này chỉ hữu ích nếu các trường hợp của công tắc C # liền kề:
case 3: blah; break;
case 4: blah; break;
case 5: blah; break;
Nhưng ít sử dụng nếu chúng không:
case 10: blah; break;
case 200: blah; break;
case 3000: blah; break;
(Bạn sẽ cần một bảng ~ 3000 mục có kích thước, chỉ có 3 vị trí được sử dụng)
Với các biểu thức không liền kề, trình biên dịch có thể bắt đầu thực hiện kiểm tra tuyến tính if-other-if-if.
Với các tập biểu thức không liền kề lớn hơn, trình biên dịch có thể bắt đầu bằng tìm kiếm cây nhị phân và cuối cùng là if-other-if-other vài mục cuối cùng.
Với các bộ biểu thức có chứa các cụm của các mục liền kề, trình biên dịch có thể tìm kiếm cây nhị phân và cuối cùng là một công tắc CIL.
Cái này chứa đầy "mays" & "mights", và nó phụ thuộc vào trình biên dịch (có thể khác với Mono hoặc Rotor).
Tôi đã sao chép kết quả của bạn trên máy của mình bằng các trường hợp liền kề:
tổng thời gian để thực hiện chuyển đổi 10 chiều, 10000 lần lặp (ms): 25.1383
thời gian gần đúng cho mỗi chuyển đổi 10 chiều (ms): 0,00251383
tổng thời gian để thực hiện chuyển đổi 50 cách, 10000 lần lặp (ms): 26.593
thời gian gần đúng cho mỗi chuyển đổi 50 cách (ms): 0,0026593
tổng thời gian để thực hiện chuyển đổi 5000 cách, 10000 lần lặp (ms): 23,7094
thời gian gần đúng cho mỗi chuyển đổi 5000 cách (ms): 0,00237094
tổng thời gian để thực hiện chuyển đổi 50000 cách, 10000 lần lặp (ms): 20,0933
thời gian gần đúng cho mỗi chuyển đổi 50000 cách (ms): 0,00200933
Sau đó, tôi cũng đã sử dụng các biểu thức trường hợp không liền kề:
tổng thời gian để thực hiện chuyển đổi 10 chiều, 10000 lần lặp (ms): 19.6189
thời gian gần đúng cho mỗi chuyển đổi 10 chiều (ms): 0,00196189
tổng thời gian để thực hiện chuyển đổi 500 cách, 10000 lần lặp (ms): 19.1664
thời gian gần đúng cho mỗi chuyển đổi 500 cách (ms): 0,00191664
tổng thời gian để thực hiện chuyển đổi 5000 cách, 10000 lần lặp (ms): 19.5871
thời gian gần đúng cho mỗi chuyển đổi 5000 cách (ms): 0,00195871
Một tuyên bố chuyển đổi trường hợp 50.000 không liền kề sẽ không biên dịch.
"Một biểu thức quá dài hoặc phức tạp để biên dịch gần 'ConsoleApplication1.Program.Main (chuỗi [])'
Điều thú vị ở đây là tìm kiếm cây nhị phân xuất hiện nhanh hơn một chút (có thể không theo thống kê) so với hướng dẫn chuyển đổi CIL.
Brian, bạn đã sử dụng từ " hằng ", có ý nghĩa rất rõ ràng từ góc độ lý thuyết phức tạp tính toán. Trong khi ví dụ số nguyên liền kề đơn giản có thể tạo ra CIL được coi là O (1) (không đổi), một ví dụ thưa thớt là O (log n) (logarit), các ví dụ cụm nằm ở đâu đó ở giữa và các ví dụ nhỏ là O (n) (tuyến tính ).
Điều này thậm chí không giải quyết được tình huống Chuỗi, trong đó một tĩnh Generic.Dictionary<string,int32>
có thể được tạo và sẽ chịu chi phí nhất định khi sử dụng lần đầu. Hiệu suất ở đây sẽ phụ thuộc vào hiệu suất của Generic.Dictionary
.
Nếu bạn kiểm tra Đặc tả ngôn ngữ C # (không phải thông số CIL), bạn sẽ thấy "15.7.2 Câu lệnh chuyển đổi" không đề cập đến "thời gian không đổi" hoặc việc triển khai cơ bản thậm chí sử dụng lệnh chuyển đổi CIL (rất cẩn thận khi giả sử những điều như vậy).
Vào cuối ngày, một công tắc C # chống lại một biểu thức số nguyên trên một hệ thống hiện đại là một hoạt động dưới micro giây và thường không đáng lo ngại.
Tất nhiên những thời gian này sẽ phụ thuộc vào máy móc và điều kiện. Tôi sẽ không chú ý đến các thử nghiệm thời gian này, thời lượng micro giây mà chúng ta đang nói đến bị lấn át bởi bất kỳ mã Real real nào đang được chạy (và bạn phải bao gồm một số mã thực tế, nếu không trình biên dịch sẽ tối ưu hóa chi nhánh), hoặc jitter trong hệ thống. Câu trả lời của tôi dựa trên việc sử dụng IL DASM để kiểm tra CIL được tạo bởi trình biên dịch C #. Tất nhiên, điều này không phải là cuối cùng, vì các hướng dẫn thực tế mà CPU chạy sau đó được tạo bởi JIT.
Tôi đã kiểm tra các hướng dẫn CPU cuối cùng thực sự được thực hiện trên máy x86 của mình và có thể xác nhận một công tắc thiết lập liền kề đơn giản thực hiện một số thứ như:
jmp ds:300025F0[eax*4]
Trường hợp tìm kiếm cây nhị phân có đầy đủ:
cmp ebx, 79Eh
jg 3000352B
cmp ebx, 654h
jg 300032BB
…
cmp ebx, 0F82h
jz 30005EEE