每个循环中的Ruby性能

每个循环中的Ruby性能,ruby,loops,Ruby,Loops,考虑以下两种ruby代码 例1 例2 对于这两段代码,想象一下 #user.rb def first_name name.split.first end 因此,在经典的算法分析中,第一段代码会更有效,然而在大多数现代编译语言中,现代编译器会优化第二段代码,使其看起来像第一段代码,从而消除了在此类语言中优化代码的需要 ruby会在执行之前优化或缓存此代码的值吗?我的ruby代码应该像示例1或示例2一样吗?示例1运行得更快,因为first_name只调用一次,它的值存储在变量中 在示例2中,R

考虑以下两种ruby代码

例1 例2 对于这两段代码,想象一下

#user.rb
def first_name
  name.split.first
end
因此,在经典的算法分析中,第一段代码会更有效,然而在大多数现代编译语言中,现代编译器会优化第二段代码,使其看起来像第一段代码,从而消除了在此类语言中优化代码的需要


ruby会在执行之前优化或缓存此代码的值吗?我的ruby代码应该像示例1或示例2一样吗?

示例1运行得更快,因为first_name只调用一次,它的值存储在变量中

在示例2中,Ruby不会自动记忆该值,因为该值可能在每个循环的迭代之间发生更改

因此,如果期望在不改变返回值的情况下多次使用计算方法,则应明确记录计算方法的开销


在做出这样的决策时,使用Ruby非常有用。只有当用户中有很多值,或者first_name的计算成本很高时,才可能值得记住。示例1运行得更快,因为first_name只调用一次,并且它的值存储在变量中

在示例2中,Ruby不会自动记忆该值,因为该值可能在每个循环的迭代之间发生更改

因此,如果期望在不改变返回值的情况下多次使用计算方法,则应明确记录计算方法的开销


在做出这样的决策时,使用Ruby非常有用。只有当用户中有很多值,或者名字计算起来很昂贵时,才有可能值得记住。

编译器只有在能够证明该方法没有副作用的情况下才能执行此优化。这在Ruby中甚至比大多数语言更困难,因为一切都是可变的,可以在运行时重写。它是否发生取决于实现,但由于在Ruby中很难做到这一点,大多数情况下不会。事实上,我不知道有任何这样做的时候,这个帖子

编译器只能在能够证明该方法没有副作用的情况下执行此优化。这在Ruby中甚至比大多数语言更困难,因为一切都是可变的,可以在运行时重写。它是否发生取决于实现,但由于在Ruby中很难做到这一点,大多数情况下不会。事实上,我不知道有任何这样做的时候,这个帖子

你有没有尝试过基准测试?也许ruby的实现依赖于ruby,但我不认为ruby会为您做到这一点我打算对它进行基准测试,但我想可能有人知道,这个问题将作为记录测试的一个好方法。对这两个例子进行基准测试将花费您几分钟的时间,并给您一个具体的答案。对这两个例子进行基准测试将花费您几分钟的时间,并在您提问的同时给您一个具体的答案。试一试,你会发现差异是微妙的,不值得费心去做,还是极端的,值得使用。你有没有尝试过基准测试?也许ruby的实现依赖于ruby,但我不认为ruby会为您做到这一点我打算对它进行基准测试,但我想可能有人知道,这个问题将作为记录测试的一个好方法。对这两个例子进行基准测试将花费您几分钟的时间,并给您一个具体的答案。对这两个例子进行基准测试将花费您几分钟的时间,并在您提问的同时给您一个具体的答案。试试看,你会发现两者之间的区别是细微的,不值得费心去做,还是极端的,值得使用。就像许多有趣的编译器优化一样,证明一个方法没有副作用,就相当于在一般情况下解决停止问题。@JörgWMittag:Yep。不过,在某些语言的特定情况下,这是可行的。例如,编译器通常可以证明访问器不会产生副作用,如OP提供的示例所示。如果一个函数所做的只是读取一些内存并返回值,而从未在堆栈外写入或调用不纯净的函数,那么它确实不会产生副作用。就像许多有趣的编译器优化一样,证明一种方法没有副作用等同于在一般情况下解决停顿问题。@JörgWMittag:Yep。不过,在某些语言的特定情况下,这是可行的。例如,编译器通常可以证明访问器不会产生副作用,如OP提供的示例所示。如果函数所做的只是读取一些内存并返回值,而不在堆栈外写入或调用未知为纯函数的函数,那么它确实不会产生副作用。
users.each do |u|
  puts "#{user.first_name} beat #{u.first_name} in #{rounds.count}"
end
#user.rb
def first_name
  name.split.first
end