Skip to content

Instantly share code, notes, and snippets.

@JonRowe
Created January 16, 2014 01:16
Show Gist options
  • Save JonRowe/8448064 to your computer and use it in GitHub Desktop.
Save JonRowe/8448064 to your computer and use it in GitHub Desktop.
TIL that `empty?` is still significantly faster than `any?` despite `any?` being lazy.
require 'benchmark'
array = 10000000.times.to_a
puts "Any"
puts Benchmark.measure { 1000.times { array.any? } }
puts "Empty"
puts Benchmark.measure { 1000.times { array.empty? } }
puts "Iterating over the entire collection"
puts Benchmark.measure { 1000.times { array.each {} } }
Any
0.000000 0.000000 0.000000 ( 0.000303)
Empty
0.000000 0.000000 0.000000 ( 0.000076)
Iterating over the entire collection
467.250000 0.150000 467.400000 (468.296172)
@lengarvey
Copy link

I thought this might be because the you're comparing C code to ruby interpreted code. But you you can also supply a block to any?

require 'benchmark'

array = 10000000.times.to_a

puts "Any"
puts Benchmark.measure { 1000.times { array.any? } }

puts "Any with a block"
puts Benchmark.measure { 1000.times { array.any?{|obj|obj} } }

puts "Empty"
puts Benchmark.measure { 1000.times { array.empty? } }

puts "Iterating over the entire collection"
puts Benchmark.measure { 10.times { array.each {} } }

Note I reduced the number of iterations on each because it's so damn slow.

Output:

Any
  0.000000   0.000000   0.000000 (  0.000272)
Any with a block
  0.000000   0.000000   0.000000 (  0.000329)
Empty
  0.000000   0.000000   0.000000 (  0.000050)
Iterating over the entire collection
  4.050000   0.000000   4.050000 (  4.053021)

I was a little surprised by this, but perhaps it optimises for the default implementation??

require 'benchmark'

array = 10000000.times.to_a

puts "Any"
puts Benchmark.measure { 1000.times { array.any? } }

puts "Any with a block"
puts Benchmark.measure { 1000.times { array.any?{|obj|obj} } }

puts "Any with a more complex block"
puts Benchmark.measure { 10.times { array.any?{|obj| obj * 2 == 5} } }

puts "Empty"
puts Benchmark.measure { 1000.times { array.empty? } }

puts "Iterating over the entire collection"
puts Benchmark.measure { 10.times { array.each {} } }

Note I have to drop the any? complex block benchmark down to 10 iterations because it's so slow.

Output:

Any
  0.000000   0.000000   0.000000 (  0.000266)
Any with a block
  0.000000   0.000000   0.000000 (  0.000323)
Any with a more complex block
  7.530000   0.000000   7.530000 (  7.528715)
Empty
  0.000000   0.000000   0.000000 (  0.000051)
Iterating over the entire collection
  4.010000   0.000000   4.010000 (  4.013209)

@JonRowe
Copy link
Author

JonRowe commented Jan 16, 2014

The complex example you provide is the worst case scenario, it never returns true so iterates over the entire collection.

@puyo
Copy link

puyo commented Jan 16, 2014

Is it the extra logic cruft around detecting no block was passed, and deciding what to do about it... ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment