这很琐碎,但已经使我烦恼了一段时间。
我有一个字符串:
x = 'abc/'
,要删除'/'令牌。
我知道这样做的最简单方法是:
x.delete!('/')
效果很好。检查对象ID:
x = 'abc/'
x.object_id # => 90851540
x.delete!('/')
x.object_id # => 90851540
x # => "abc"
对象ID保持不变,所以我得出结论Ruby修改了x
AS-IS,而无需生成新副本。
最好检查字符串是否实际上具有"/"字符将delete!()
应用于它?
我记得有人曾经说过"没关系"由于delete!()
无论如何都会检查给定的字符串,并且仅在字符串具有字符时进行修改。
这很公平。
,但我想知道两者的利弊方法。会:
if x.include? '/'
更快?会更好或更方便吗?
在代码中可能更清晰,但是也使代码更详细,也许也可能导致一些开销。
有时我单独使用delete!()
,而无需任何检查,有时我会进行检查。
是比其他,因为现在我有点赞成"不检查",不是因为速度原因,而是因为由于语法/较少的代码。
我可能会选择delete!
,而无需检查大多数时间("少代码"并且仍然清晰(,但让我们评估绩效:
test.rb
require 'benchmark'
iterations = 1_000_000
puts "'/' ALWAYS PRESENT"
Benchmark.bmbm do |bm|
bm.report('without if') do
iterations.times do
x = "abc/"
x.delete!("/")
end
end
bm.report('with if') do
iterations.times do
x = "abc/"
x.delete!("/") if x.include?("/")
end
end
end
puts "n'/' NEVER PRESENT"
Benchmark.bmbm do |bm|
bm.report('without if') do
iterations.times do
x = "abc"
x.delete!("/")
end
end
bm.report('with if ') do
iterations.times do
x = "abc"
x.delete!("/") if x.include?("/")
end
end
end
结果
'/' ALWAYS PRESENT
Rehearsal ----------------------------------------------
without if 0.540000 0.000000 0.540000 ( 0.541003)
with if 0.630000 0.010000 0.640000 ( 0.632728)
------------------------------------- total: 1.180000sec
user system total real
without if 0.510000 0.000000 0.510000 ( 0.513438)
with if 0.630000 0.000000 0.630000 ( 0.632055)
'/' NEVER PRESENT
Rehearsal ----------------------------------------------
without if 0.510000 0.000000 0.510000 ( 0.513233)
with if 0.190000 0.000000 0.190000 ( 0.194709)
------------------------------------- total: 0.700000sec
user system total real
without if 0.510000 0.000000 0.510000 ( 0.514632)
with if 0.180000 0.000000 0.180000 ( 0.186374)
基于此结果,我们看到(正如人们可能期望的(删除之前的检查(由于该额外检查(比仅删除 该字符串包含 /
。但是,当不存在/
时,首先检查速度要快得多。
因此,从性能的角度来看,如果您期望没有/
的情况很高,则可能需要使用include?
。
如果您想知道A 50%/50%方案会是什么样,这是测试:
test.rb
require 'benchmark'
iterations = 500_000
puts "n'/' PRESENT IN 50%"
Benchmark.bmbm do |bm|
bm.report('without if') do
iterations.times do
x = "abc/"
x.delete!("/")
end
iterations.times do
x = "abc"
x.delete!("/")
end
end
bm.report('with if ') do
iterations.times do
x = "abc/"
x.delete!("/") if x.include?("/")
end
iterations.times do
x = "abc"
x.delete!("/") if x.include?("/")
end
end
end
结果
'/' PRESENT IN 50%
Rehearsal ----------------------------------------------
without if 0.540000 0.010000 0.550000 ( 0.554114)
with if 0.410000 0.000000 0.410000 ( 0.419098)
------------------------------------- total: 0.960000sec
user system total real
without if 0.540000 0.000000 0.540000 ( 0.549411)
with if 0.410000 0.000000 0.410000 ( 0.420603)
我不会出于简单的原因检查它是多余的。即使我检查了令牌的存在,Ruby还是要再次检查它(无法跳过它(。我看到的一个问题是NIL检查,变量可能为零。在这种情况下,我也会做类似variable.to_s.delete!()
的事情。因此,我认为我有足够的理由跳过检查/验证令牌的存在,并且没有理由进行防御编码。