if vs Ruby 中的短路评估

时间:2021-01-11 00:44:53

标签: ruby

我想知道是什么让 if 比我的代码中的短路评估更快:

GC.disable
N = 5000

def x
    j = nil
    N.times {
        if j
            j << 'a'.freeze
        else
            j = ''
        end
    }
    j
end

def y
    j = nil
    N.times {
        j && j << 'a'.freeze || j = ''
    }
    j
end

t = Time.now
N.times { x }
p Time.now - t

sleep 0.1

t = Time.now
N.times { y }
p Time.now - t

无论我在没有额外 CPU 负载的情况下运行代码多少次,我都会得到:

3.826009846
4.137173916

或类似的东西。

整数也是一样,稍微修改一下代码,让j=nil,然后0,然后j加上+1。

是什么让方法 y 比方法 x 慢?

1 个答案:

答案 0 :(得分:0)

根据评论更新。这是一种改进 x 方法的方法。 B 是您的方法,C 是改进版本,因为使用这种语法, && 的右侧永远不会被执行。 Benchmark 是标准的 Ruby 方式,它准确地执行该类旨在用于易于阅读文档的操作。要了解为什么不推荐使用 INT IDENTITY,请参阅 this answer。此外,将迭代移至基准测试是很常见的,以免弄乱您的实际方法。

Time.now

结果:

require 'benchmark'
GC.disable

N=50000

class Foo
  def a
    j = nil
    if j
        j << 'a'.freeze
    else
        j = 'not nil'
    end
    j
  end

  def b
    j = nil
    j && j << 'a'.freeze || j = 'not nil'
    j
  end

  def c
    j = nil
    j && (j << 'a' || j = 'j')
    j
  end
end
foo = Foo.new
foo.a
foo.b
foo.c
Benchmark.bmbm(10) do |x|
  x.report(:a) { N.times {foo.a }}
  puts "j is no longer nil, but it's a string #{foo.a} <- see"
  x.report(:b) { N.times {foo.b }}
  puts "j is equal to #{foo.b} which is a string, not nil"
  x.report(:c) { N.times {foo.c }}
  puts "look for j, nothing here *#{foo.c}* but emptiness"
end

puts "\n take 2\n"

Benchmark.bmbm(10) do |x|
  x.report(:c) { N.times {foo.c }}
  x.report(:a) { N.times {foo.a }}
  x.report(:b) { N.times {foo.b }}
end
相关问题