Performance comparison: throw(:abort)
vs. raise ActiveSuppot::CallbackAborted
#################################################################################
In the current Rails stable (4.2) and master (5.0.0.alpha), callbacks can be halted with return false
.
PR #17227 replaces this behavior with an explicit throw(:abort)
.
In a comment, @tenderlove asks whether this will have a significant impact on the performance, and whether it would be better (performance-wise) to use a raise/rescue construct instead.
The code below can be used to benchmark the impact of these different strategies on ActiveRecord callbacks. Notice that PR #17227 also changes ActiveModel and ActiveSupport callback, but this benchmark only focuses on ActiveRecord.
I created a scaffold model Post with a string field Title. Then I benchmark the code to create a new Post under different sets of callbacks:
Post
has no callbacks at allPostWithPassingCallbacks
has callbacks that always returntrue
PostWithFalseCallback
has one callback that returnsfalse
PostWithThrowingCallback
has one callback that callsthrow :abort
PostWithRaisingCallback
has one callback that callsraise ActiveSupport::CallbackAborted
These are my observations:
- [Comparing z1 with z2] The current 5.0.0.alpha is already faster than 4.2.0 (stable) under every condition. This is not related to PR #17227 but good to know.
- [Comparing z2 with z3/z4] Replacing
return false
with a different strategy (either throw/catch or raise/rescue) slightly decreases the performance in some conditions and slightly increases the performance in other conditions. - [Comparing z4 with z3] Raising/rescuing an error rather than throwing/catching an exception does not have a significantly positive impact on performance
According to these results, my opinion is to keep PR #17227 as it is, using throw(:abort)
rather than raise ActiveSupport::CallbackAborted
. This favors readability of code as well.