# Benchmarks Project and example for \`||=\`

**URL:** <https://www.ruby-forum.com/t/benchmarks-project-and-example-for/196127>\
**Category:** Ruby\
**Created:** [October 7, 2010, 6:29am UTC](https://www.ruby-forum.com/t/benchmarks-project-and-example-for/196127 "2010-10-07T06:29:18Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![tcsnide](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/eb8c5e/32.png) [@tcsnide](https://www.ruby-forum.com/u/tcsnide)\
**Post date:** [October 7, 2010, 6:29am UTC](https://www.ruby-forum.com/t/benchmarks-project-and-example-for/196127/1 "2010-10-07T06:29:18Z")

</div>

Has anyone ever put together a suite of benchmarks that simply measure  
interesting Ruby practices? For example, here is a comparison of using  
||= vs not using it.

n = 1000000

puts “#{n} Times”

t = Time.now

@b = :b  
n.times do  
@b  
end

puts “Simple Read : #{Time.now - t} seconds”

t = Time.now

n.times do  
@a ||= :a  
end

puts " Or Equals : #{Time.now - t} seconds"

On `ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux]`:

1000000 Times  
Simple Read : 0.395487 seconds  
Or Equals : 0.508428 seconds

On `ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-linux]`:

1000000 Times  
Simple Read : 0.121280356 seconds  
Or Equals : 0.183629043 seconds

Might be an interesting project.

---

<div class="post-metadata">

**Author:** ![tcsnide](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/eb8c5e/32.png) [@tcsnide](https://www.ruby-forum.com/u/tcsnide)\
**Post date:** [October 7, 2010, 6:57am UTC](https://www.ruby-forum.com/t/benchmarks-project-and-example-for/196127/2 "2010-10-07T06:57:58Z")

</div>

On Thu, Oct 7, 2010 at 7:28 AM, Intransition [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> @b = :b  
> end
> 
> 1000000 Times  
> Simple Read : 0.121280356 seconds  
> Or Equals : 0.183629043 seconds
> 
> Might be an interesting project.

It would be interesting to have performance comparisons of the various  
idioms in common use.

In these examples, however, it’s not surprising that the first loop  
(without  
||=) would be faster. It’s not doing anything really. The second involves  
testing wether the variable is defined or not, every iteration.

Regards,  
Ammar

---

<div class="post-metadata">

**Author:** ![tcsnide](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/eb8c5e/32.png) [@tcsnide](https://www.ruby-forum.com/u/tcsnide)\
**Post date:** [October 7, 2010, 3:29pm UTC](https://www.ruby-forum.com/t/benchmarks-project-and-example-for/196127/3 "2010-10-07T15:29:00Z")

</div>

On Oct 7, 12:57 am, Ammar A. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> It would be interesting to have performance comparisons of the various  
> idioms in common use.
> 
> In these examples, however, it’s not surprising that the first loop (without  
> ||=) would be faster. It’s not doing anything really. The second involves  
> testing wether the variable is defined or not, every iteration.

Yep. I wrote it b/c I wanted to know _how much_ slower using ||= is.

---

<div class="post-metadata">

**Author:** ![tcsnide](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/eb8c5e/32.png) [@tcsnide](https://www.ruby-forum.com/u/tcsnide)\
**Post date:** [October 7, 2010, 6:56pm UTC](https://www.ruby-forum.com/t/benchmarks-project-and-example-for/196127/4 "2010-10-07T18:56:18Z")

</div>

On Thu, Oct 7, 2010 at 12:05 PM, Jeremy B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> The point of comparison profiling like this is to find ways to improve  
> your code without changing its ultimate function. Your comparison here  
> compares two fundamentally different operations

It struck me as odd that Trans is benchmarking two different things  
against each other.

As another example, I just benchmarked the time it takes me to get up  
out of my sofa and walk to my front door and back at about 30 seconds.  
That’s over 3 times FASTER than Fernando Alonso’s fastest lap of  
1:47.976 in the Singapore Grand Prix a couple of Sunday’s ago.

So does that make me faster than a Ferrari F10, I don’t think so, and  
I doubt that it has a practical significance.

–  
Rick DeNatale

Help fund my talk at Ruby Conf 2010:[http://pledgie.com/campaigns/13677](http://pledgie.com/campaigns/13677)  
Blog: [http://talklikeaduck.denhaven2.com/](http://talklikeaduck.denhaven2.com/)  
Github: [rubyredrick (Rick DeNatale) · GitHub](http://github.com/rubyredrick)  
Twitter: @RickDeNatale  
WWR: [http://www.workingwithrails.com/person/9021-rick-denatale](http://www.workingwithrails.com/person/9021-rick-denatale)  
LinkedIn: [http://www.linkedin.com/in/rickdenatale](http://www.linkedin.com/in/rickdenatale)

---

<div class="post-metadata">

**Author:** ![tcsnide](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/eb8c5e/32.png) [@tcsnide](https://www.ruby-forum.com/u/tcsnide)\
**Post date:** [October 7, 2010, 6:05pm UTC](https://www.ruby-forum.com/t/benchmarks-project-and-example-for/196127/5 "2010-10-07T18:05:56Z")

</div>

On 10/7/2010 8:28 AM, Intransition wrote:

> Yep. I wrote it b/c I wanted to know _how much_ slower using ||= is.  
> The issue is one of relevance though. Of course using ||= is slower  
> than simply taking whatever value is in the variable, but why do you  
> care in the first place?

If you just wanted to take the value of a variable, you would never use  
||= in the first place. If you have a need to assign a value to the  
variable only if it’s not already defined though, then you need ||= or  
one of its less idiomatic equivalents.

The point of comparison profiling like this is to find ways to improve  
your code without changing its ultimate function. Your comparison here  
compares two fundamentally different operations. A more relevant  
comparison would be as follows:

n = 1000000

puts “#{n} Times”

t = Time.now

@c = :c  
n.times do  
@c = :c unless @c  
@c  
end

puts " Optional set then get (verbose) : #{Time.now - t} seconds"

t = Time.now

@b = :b  
n.times do  
@b = @b || :b  
end

puts “Optional set then get (less verbose) : #{Time.now - t} seconds”

t = Time.now

n.times do  
@a ||= :a  
end

puts " Optional set then get (idiomatic) : #{Time.now - t} seconds"

ruby 1.9.2p0 (2010-08-18) [i386-mingw32]  
1000000 Times  
Optional set then get (verbose) : 0.125004 seconds  
Optional set then get (less verbose) : 0.140628 seconds  
Optional set then get (idiomatic) : 0.156254 seconds

ruby 1.8.7 (2010-06-23 patchlevel 299) [i386-mingw32]  
1000000 Times  
Optional set then get (verbose) : 0.20313 seconds  
Optional set then get (less verbose) : 0.218756 seconds  
Optional set then get (idiomatic) : 0.187505 seconds

In this light, the idiomatic method compares favorably; however, I do  
find it odd that Ruby 1.9.2 seems to take a hit on the relative  
performance of the idiomatic method as compared to Ruby 1.8.7.

-Jeremy

---

<div class="post-metadata">

**Author:** ![tcsnide](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/eb8c5e/32.png) [@tcsnide](https://www.ruby-forum.com/u/tcsnide)\
**Post date:** [October 8, 2010, 12:56am UTC](https://www.ruby-forum.com/t/benchmarks-project-and-example-for/196127/6 "2010-10-08T00:56:15Z")

</div>

On 10/7/2010 5:11 PM, Intransition wrote:

> > 
> 
> is in fact a very good reason for my comparison. I often do:  
> speed, I would do:  
> The purpose of the benchmark was to see just how much “squeeze” I am  
> getting in the exchange.

Take a look at  
[Programming Ruby: The Pragmatic Programmer's Guide](http://ruby-doc.org/docs/ProgrammingRuby/html/classes.html). On that  
page you’ll find some examples for defining a method named “once”.  
Search for “ExampleDate.once” under the Class and Module Definitions  
section.

You can use the “once” method as a directive that will ensure that a  
given method which may be expensive to compute is only run 1 time after  
which the cached value will be returned. I made a generalized version  
of “once” as suggested there for use in an internal project where I  
work. That way I get the best of delayed computation, clear code, and  
fast results for a few methods that really need it.

It might be interesting to profile the performance of a method wrapped  
by “once” compared to your other solutions.

-Jeremy

---

<div class="post-metadata">

**Author:** ![tcsnide](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/eb8c5e/32.png) [@tcsnide](https://www.ruby-forum.com/u/tcsnide)\
**Post date:** [October 8, 2010, 12:18am UTC](https://www.ruby-forum.com/t/benchmarks-project-and-example-for/196127/7 "2010-10-08T00:18:47Z")

</div>

On Oct 7, 12:45 pm, Rick DeNatale [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> That’s over 3 times FASTER than Fernando Alonso’s fastest lap of  
> 1:47.976 in the Singapore Grand Prix a couple of Sunday’s ago.
> 
> So does that make me faster than a Ferrari F10, I don’t think so, and  
> I doubt that it has a practical significance.

I think this is a good a reminder as any that it’s hard to see what  
someone else is getting at when you’re not seeing the use case. There  
is in fact a very good reason for my comparison. I often do:

class X  
def f  
@f ||= ( do\_some\_calc\_or\_lookup )  
end  
end

I like this idiom as it provides the speed bump of caching and yet  
encapsulates the entire procedure for getting the value in one place.  
However, if I am really concerned about squeezing out every bit of  
speed, I would do:

class X  
def initialize  
@f = ( do\_some\_calc\_or\_lookup )  
end  
def f  
@f  
end  
end

The purpose of the benchmark was to see just how much “squeeze” I am  
getting in the exchange.

---

<div class="post-metadata">

**Author:** ![tcsnide](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/eb8c5e/32.png) [@tcsnide](https://www.ruby-forum.com/u/tcsnide)\
**Post date:** [October 8, 2010, 3:43am UTC](https://www.ruby-forum.com/t/benchmarks-project-and-example-for/196127/8 "2010-10-08T03:43:34Z")

</div>

On Oct 7, 2010, at 15:11 , Intransition wrote:

> end  
> There is a damn good reason why lazy initializing exists in the first  
> place, and it invalidates your statement above.

If you were **really** concerned about squeezing out every bit of speed,  
you’d profile the code to see how it is used. If #f isn’t being called  
in a tight loop, or isn’t even being called much at all, then you might  
be spending more time running initialize than you would have doing the  
lazy initialize. You’ll never know that mentarbating over  
micro-benchmarks.

---

<div class="post-metadata">

**Author:** ![tcsnide](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/eb8c5e/32.png) [@tcsnide](https://www.ruby-forum.com/u/tcsnide)\
**Post date:** [October 8, 2010, 8:42am UTC](https://www.ruby-forum.com/t/benchmarks-project-and-example-for/196127/9 "2010-10-08T08:42:34Z")

</div>

On Oct 7, 9:27 pm, Ryan D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > ```
> > @f
> > 
> > ```
> > 
> > end  
> > end
> 
> There is a damn good reason why lazy initializing exists in the first place, and it invalidates your statement above.

How?

> If you were **really** concerned about squeezing out every bit of speed, you’d profile the code to see how it is used. If #f isn’t being called in a tight loop, or isn’t even being called much at all, then you might be spending more time running initialize than you would have doing the lazy initialize. You’ll never know that mentarbating over micro-benchmarks.

You assume I am not aware of how frequently X.new is bring called in  
comparison to X#f. In my case, its about 1 to N where N \>= 1, and so  
forth for X#f2, X#f3, X#f4, etc. If #f wasn’t being used but on rare  
occasion, I wouldn’t worry about it. Moreover, by knowing the relative  
difference between the two, one can make a better effort at optimizing  
upfront, and potentially save time later.

And yes I do indeed profile code when I am “ **really** concerned about  
squeezing out every bit of speed”. In fact, if memory serves, I was  
doing exactly that when I was trying to decide if giving up the  
convenience of ||= was worth the performance gain.
