Tôi luôn nghi ngờ mạnh mẽ rằng các ngoại lệ sẽ chậm trong ruby so với các cơ chế kiểm soát dòng chảy khác. Xét cho cùng - các trường hợp ngoại lệ phức tạp hơn rất nhiều so với "break" hoặc "return" đơn giản. Nhưng linh cảm của tôi đã sai trước đây, vì vậy tôi nghĩ rằng tôi nên thử nghiệm nó.
Trong đoạn mã bên dưới, tôi đang sử dụng viên ngọc benchmark-ips để so sánh hiệu suất tương đối của việc thoát khỏi một vòng lặp thông qua ngoại lệ, ngắt và trả về. Tôi đã thấy các ví dụ trên web về những người làm các điểm chuẩn như thế này với mri 1.9. Nhưng tôi muốn dùng thử với mri 2.2.
require 'benchmark/ips'
def exit_via_exception
5.times do
raise RuntimeError
end
rescue
end
def exit_via_break
5.times do
break
end
end
def exit_via_return
5.times do
return
end
end
Benchmark.ips do |x|
x.report("exception") { exit_via_exception }
x.report("break") { exit_via_break }
x.report("return") { exit_via_return }
end
Kết quả là khá đáng kinh ngạc. Hàm sử dụng ngoại lệ nhanh hơn một nửa so với hàm sử dụng ngắt và trả lại.
$ ruby exception_benchmark.rb
Calculating -------------------------------------
exception 50.872k i/100ms
break 125.322k i/100ms
return 124.173k i/100ms
-------------------------------------------------
exception 714.795k (± 2.7%) i/s - 3.612M
break 3.459M (± 3.1%) i/s - 17.294M
return 3.379M (± 3.0%) i/s - 16.888M
Đây không phải là điểm chuẩn hoàn hảo
Có một số vấn đề mà tôi không biết phải làm thế nào để bù đắp. Ví dụ, các phương thức ngoại lệ và ngắt phải trả về. Vì vậy, họ đang làm nhiều hơn là phương thức chỉ trả về. Ngoài ra, tôi muốn xem liệu việc giải cứu ngoại lệ có làm tăng chi phí hiệu suất hay không. Nhưng không giải cứu nó sẽ khiến điểm chuẩn bị hủy bỏ.
Tuy nhiên, ngoại lệ chậm hơn nhiều so với các ví dụ khác mà tôi nghĩ rằng kết quả có ý nghĩa ngay cả khi chúng không hoàn hảo.
Bài học chúng ta đã học?
Nếu bạn đang sử dụng ngoại lệ làm cơ chế kiểm soát luồng. Dừng lại ngay! Đặc biệt là nếu bạn có một vòng lặp bao gồm các ngoại lệ được đưa ra và bị bắt lặp đi lặp lại.
Điều này sẽ thay đổi cách cá nhân tôi sử dụng các ngoại lệ? Chắc là không. Tôi có thể sống với một chút chậm chạp nếu sự chậm chạp là một ngoại lệ của quy luật. :)
... Nhưng JRuby và RBx thì sao?
Josh Cheek (@josh_cheek trên twitter) đã viết phiên bản của riêng mình về điểm chuẩn này, phiên bản toàn diện hơn của tôi. Và anh ấy đã chạy nó với nhiều lần triển khai ruby. Bạn có thể xem kết quả của anh ấy ở đây. Rõ ràng break vẫn là người chiến thắng. :)