-
Notifications
You must be signed in to change notification settings - Fork 376
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parallel versus sequential assignment is microbenchmark (not representative) and scales with number of inputs #208
Comments
But only because the code you used is: report = MemoryProfiler.report do
_a, _b = 1, 2
end Can you try with: report = MemoryProfiler.report do
_a, _b = 1, 2
nil
end Then there should be no extra array allocation. I agree measuring with 2 elements is more representative. I think the conclusion should be: sequential/parallel assignments are basically the same speed. FWIW, I personally think fast-ruby is not a good resource for "what one should use". It all depends on the Ruby version, implementation, context, how it's used, etc, etc. |
Quick numbers: require 'benchmark/ips'
def parallel
_a, _b = 1, 2
# nil
end
def sequential
_a = 1
_b = 2
# nil
end
Benchmark.ips do |x|
x.report('Parallel Assignment') { parallel }
x.report('Sequential Assignment') { sequential }
x.compare!
end With the
So it's the same speed (and sequential is not any faster for this case, it'd just be noise). With the
As expected Sequential is much faster here, because Parallel must do an array allocation with the Parallel Assignment as last expression. |
And with MemoryProfiler:
|
Thanks for catching that. The |
I believe that's just noise or too small to matter. I ran it 3 times locally, and the first I got Sequential 1.02x slower, 2nd and 3rd run I know you'd like Sequential Assignment to be faster, but it's not true/not that simple in general. For a general Ruby JIT, there should be no significant difference in generated code between both kind of assignments (for the non-last-expression case). |
To illustrate this point, we can use
So it's literally the same instructions, just in a slightly different order in CRuby 3.1.2. |
I understand the limits of the measurements and statistics. I'm able to detect a 1% request speedup with 99% confidence in a Rails app end to end. Via derailed https://github.com/zombocom/derailed_benchmarks/blob/0102612a9915179abca304ad0392aa84ed6bdf0e/lib/derailed_benchmarks/stats_from_dir.rb#L143-L165. I generally try annotating with things like If we're talking probability. I would say my prior was strong that parallel assignment allocates, then you came along and made a chip in that prior, then adam came along and told me what I wanted to hear. I'm not being intentionally misleading, but I am very much intentionally trying to prove or disprove that concept to myself.
100% agreed here. It's an interesting trivia night question, but won't affect IRL performance.
Fascinating 🤷🏻♂️. Thanks for all the extra info |
Update: Parallel assignment doesn't allocate unless it's the last statement in a method/proc. There's a benchmark provided below. I'm
I think this benchmark https://github.com/fastruby/fast-ruby/blob/main/code/general/assignment.rb needs to be removed or at least heavily annotated on the readme. It is not representative of real code. In my experience, removing parallel assignments into sequential ones speeds up apps.
One reason is that parallel assignments [can] allocate an intermediate array [if it is the last statement in a method for example], the other is that the benchmark uses MANY assignments and the performance difference seems to scale with assignment numbers. In the wild the most common number is 2.
Also worth noting that by using integers, we're isolating to only the assignment time (mostly) but this distorts the possible impact of the code. If you switch to strings that allocate then the pressure on the GC actually causes sequential assignment to be faster (at least sometimes).
Benchmarks below.
Reasoning
In https://github.com/fastruby/fast-ruby/blob/main/code/general/assignment.rb it states that parallel assignment is much faster than sequential assignment, but if you have only 2 assignments, the difference is negligible:
Note that sequential assignment is faster here (but within error). While the parallel assignment is fewer operations, it also introduces an intermediate array that requires an allocation:
Even in the case of MANY sequential versus parallel assignments, if the function is doing anything non-trivial (such as allocating strings as opposed to using integers which are all singletons, then the effect of the "faster" parallel assignment is pretty much negligible. This run actually has sequential being faster:
The sequential assignment is also faster here (but within error).
The text was updated successfully, but these errors were encountered: