Ruby Fixnum#to#u的性能问题
我有以下算法(它搜索二进制表示也是回文的回文): 但如果我改变Ruby Fixnum#to#u的性能问题,ruby,Ruby,我有以下算法(它搜索二进制表示也是回文的回文): 但如果我改变 while current <= @max string = current.to_s if string == string.reverse && current.to_s(2) == current.to_s(2).reverse 虽然我希望它会更快(所需的计算更少),但速度要慢两倍。同时#to#s不带参数按预期工作,如果我删除变量并执行两次计算: while cu
while current <= @max
string = current.to_s
if string == string.reverse && current.to_s(2) == current.to_s(2).reverse
虽然我希望它会更快(所需的计算更少),但速度要慢两倍。同时#to#s不带参数按预期工作,如果我删除变量并执行两次计算:
while current <= @max
if current.to_s == current.to_s.reverse && current.to_s(2) == current.to_s(2).reverse
查看没有帮助理解它,除非问题与
else
条件分支有关。但我找不到任何问题。有人能解释为什么它是这样工作的吗(我使用的是MRI 2.1.1p76)?在Ruby中,当你有一个类似
a && b
首先计算a
,如果为false,则不计算b
Base10回文很少,因此对于循环中的绝大多数循环,原始代码只检查string==string.reverse
为false,然后继续循环的下一次迭代。因此,您只需对s执行一次,对s(2)
执行一对
其他更改集都会更频繁地调用到_
,从而做更多的工作,因此速度较慢。对我来说并不奇怪。在您的原始版本中,当前.to_s(2)
仅在字符串==string.reverse
时计算,因为&&
短路。相当于:
while current <= @max
string = current.to_s
if string == string.reverse
string_b = current.to_s(2)
if string_b == string_b.reverse
当前在探查器中分析此代码时,似乎大部分时间都花在fix\u to_s()
C调用中
跳转到fix_to_s()
的汇编代码中,我们看到它的大部分时间都花在一条指令上movslq%edx,%rdx
。显然,movslq
is将长(32位)移动到四位(64位)中
在您记忆string2
的代码版本中,我们有3027个movslq
样本,而在非记忆版本中,我们只有700个样本!有什么好处
在记忆版本中,似乎分配了更多的字符串对象,从而被ruby解释器释放。请注意创建和释放字符串对象所花费的时间
我使用allocation\u stats
gem运行了一些关于对象分配的统计数据,它们表明在非记忆版本中分配的字符串确实更少。大约是总数的三分之二
test.rb字符串20032954
vs
test.rb字符串30010967
当您显式设置string2=current.to_s(2)
时,他们必须为您分配内存,因为您可能需要它。但是,在您的代码中,它不一定要执行&&
语句的第二部分,因此您可以完全避免这种分配
显然,增加分配量会在许多方面降低速度,包括使缓存未命中的可能性更大、垃圾收集更多,以及更多的free()
ing和malloc()
ing,这解释了为什么分配/时间的关系不是线性的。trushkevich,你能报告这次修改的时间吗?我猜是2.52秒,是的,我忽略了。当然,当我写剧本时,我一直在思考这个问题。很抱歉,我接受了托德·阿古尼克的说法,只是因为他的名声不好。卡里·斯沃夫兰,仅运行一次脚本就很难准确判断,它的大小从2.48s.
到2.62s.
。我认为结论是,将字符串b=current.to_s(2)
添加到几乎没有什么区别。你有三个好答案,你真幸运。啊,当然!一点也不奇怪!不久前我写了这个脚本,后来当我打开文件时,出于某种原因,我没有考虑&&
,并开始认为有什么问题。无论如何谢谢你!谢谢你的分析!很有帮助,而且赏心悦目。
Time spent: 6.25 s.
while current <= @max
if current.to_s == current.to_s.reverse && current.to_s(2) == current.to_s(2).reverse
Time spent: 4.17 s.
a && b
while current <= @max
string = current.to_s
if string == string.reverse
string_b = current.to_s(2)
if string_b == string_b.reverse