Ruby:While和Until循环之间的速度差异是什么?

时间:2017-08-02 02:20:38

标签: ruby

我现在正在学习Ruby。在过去几年中使用Javascript,我熟悉While循环。但直到循环?我环顾四周,却找不到一个比另一个好的原因。

Ruby有“until”,它被描述为另一种表达问题的方式。我看到它的方式,“while”迭代直到false,“until”迭代直到true。

我确信我编写的大多数程序都不需要重构速度。但是,我有时想深入了解一些细节。

两个循环之间是否存在速度差异?为什么Ruby中有“until”语法?为什么不坚持“while?”

3 个答案:

答案 0 :(得分:5)

whileuntil之间没有速度差异,因为它们互为镜像。

我们会将while循环与until循环进行比较:

n = 0
puts n += 1 while n != 3

n = 0
puts n += 1 until n == 3

这些都会打印1到3。

这是来自Ruby VM的两个反汇编的人类可读指令序列之间的区别:

@@ -13,7 +13,7 @@
 0021 pop              
 0022 getlocal_OP__WC__0 2
 0024 putobject        3
-0026 opt_neq          <callinfo!mid:!=, argc:1, ARGS_SIMPLE>, <callcache>, <callinfo!mid:==, argc:1, ARGS_SIMPLE>, <callcache>
-0031 branchif         8
-0033 putnil           
-0034 leave
+0026 opt_eq           <callinfo!mid:==, argc:1, ARGS_SIMPLE>, <callcache>
+0029 branchunless     8
+0031 putnil           
+0032 leave

while循环使用branchif进行跳转,而until循环使用branchunless。因此,这些循环只是在进行比较时有所不同,您可以通过查看branchifbranchunless defined的方式来看到:

DEFINE_INSN
branchif
(OFFSET dst)
(VALUE val)
()
{
    if (RTEST(val)) {
    RUBY_VM_CHECK_INTS(th);
    JUMP(dst);
    }
}
DEFINE_INSN
branchunless
(OFFSET dst)
(VALUE val)
()
{
    if (!RTEST(val)) {
    RUBY_VM_CHECK_INTS(th);
    JUMP(dst);
    }
}

whileuntil之间的效果几乎相同。用法应由可读性决定。

答案 1 :(得分:3)

除了速度差异之外,它实际上都是关于可读性的,这是Ruby引以为豪的。

让我们假装我们正在喝酒 - 您认为哪种饮料更好?

A) pour_drink until glass.full?
B) pour_drink while !glass.full?

答案 2 :(得分:3)

选择比较运算符会比选择whileuntil

更加影响速度
Benchmark.bmbm do |bm|
  bm.report('while') do
    n = 0
    n += 1 while n != 10_000_000
  end

  bm.report('until') do
    n = 0
    n += 1 until n == 10_000_000
  end
end

            user     system      total        real
while   0.250000   0.000000   0.250000 (  0.247949)
until   0.220000   0.000000   0.220000 (  0.222049)

while n != 10_000_000until n == 10_000_000相比,until似乎更快。

Benchmark.bmbm do |bm|
  bm.report('while') do
    n = 0
    n += 1 while n < 10_000_000
  end

  bm.report('until') do
    n = 0
    n += 1 until n == 10_000_000
  end
end

            user     system      total        real
while   0.210000   0.000000   0.210000 (  0.207265)
until   0.220000   0.000000   0.220000 (  0.223195)

将其更改为while n < 10_000_000,现在while似乎有优势。公平地说,我们应该给他们更加相同的while n < 10_000_000until n > 9_999_999

Benchmark.bmbm do |bm|
  bm.report('while') do
    n = 0
    n += 1 while n < 10_000_000
  end

  bm.report('until') do
    n = 0
    n += 1 until n > 9_999_999
  end
end

            user     system      total        real
while   0.200000   0.000000   0.200000 (  0.208428)
until   0.200000   0.000000   0.200000 (  0.206218)

现在他们几乎完全相同。因此,请遵循Ruby的主导,并通过类似英语句子的代码获得满意度。但请确保使用<>来获得额外的.0000000001秒的提升。