【问题标题】:Slow Ruby for simple array operations用于简单数组操作的慢速 Ruby
【发布时间】:2015-07-19 19:35:59
【问题描述】:

我按照 Cormen 的“算法简介”中的伪代码在 Ruby 中创建了简单的插入排序实现:

def sort_insert(array)
  (1 ... array.length).each do |item_index|
    key = array[item_index]
    i = item_index - 1

    while i >= 0 && array[i] > key do
      array[i + 1] = array[i]
      i -= 1
    end
    array[i + 1] = key
  end
  array
end

它可以工作,但执行速度很慢。对于 ~20k 元素数组 array = ((0..10_000).to_a * 2).shuffle,排序大约需要 20 秒。我只测量这个方法调用的时间,没有数据准备等。在 JavaScript 中,一个非常相似的解决方案大约需要 1 秒。为什么 Ruby (v. 2.2.2p95) 在这里这么慢?

编辑: 这个排序的JS版本,我用的:

function SortMethods() {
}

SortMethods.prototype.sortInsert = function(array) {
  for(let itemIndex = 1; itemIndex < array.length; itemIndex++) {
    let key = array[itemIndex];
    let i = itemIndex - 1;

    while( i >= 0 && array[i] > key) {
      array[i + 1] = array[i];
      i--;
    }
    array[i + 1] = key;
  }

  return array;
}

【问题讨论】:

  • 在我的笔记本电脑上对 20k 个随机数进行排序大约需要 5.9 秒 (a = Array.new(20_000) { rand })。无法与 JS 相提并论,因为我不是 JS 程序员,但对于具有 20k 值的 O(N^2) 算法,我发现约 6 秒并不令人震惊。相比之下,使用a.sort! 需要 0.01 秒,这对我来说已经足够快了。
  • 对我来说,这个问题听起来像,“为什么我的刀不切,如果我倒置使用它”
  • 您可以使用ruby-prof 了解 Ruby 是如何花费时间的。但是,不同语言的两种实现之间存在 20 倍的速度差异也就不足为奇了。你甚至没有说正在使用什么 Javascript 实现,所以很难评论差异。
  • 我认为所提出的问题基本上是无法回答的,或者至少没有任何有用或有意义的方式。 “为什么 A 与 B 不同?”的正确但无用的答案是“因为 A 和 B 不同。”
  • @HunterStevens 是的,我已经编写了相同算法的 JS 版本,并说我想知道为什么 Ruby 实现与 Javascript 相比要慢得多。我在问题中包含了这两个代码。

标签: ruby performance


【解决方案1】:

我不同意你的问题的前提——Ruby 在我的机器上带来的不仅仅是可观的性能。

为了说明这一点,我创建了一个包含 100k 随机数的文件:

$ ruby -e '100_000.times {printf "%22.20f\n", rand}' > rand100k.csv

然后我使用系统排序实用程序对其进行排序,保存结果以供以后比较(作为正确性检查):

$ time sort -n < rand100k.csv > foo

real    0m0.067s
user    0m0.056s
sys     0m0.011s

我在纯 ruby​​ 中编写了一个快速排序算法(当子列表大小变得足够小时,它会切换到插入排序),运行它,保存结果,并区分系统排序输出和 ruby​​ 输出文件:

$ time ruby quicksort_w_insertion.rb < rand100k.csv > bar

real    0m0.546s
user    0m0.537s
sys 0m0.008s
$ diff foo bar
$

如您所见,两次排序运行都会产生相同的输出,而且速度非常快。在我看来,一个仅比相应系统实用程序慢 8-10 倍的纯 Ruby 程序在速度方面做得非常好。

这些运行是在 MacBook Pro 上使用 ruby 2.2.2p95 (2015-04-13 revision 50293) [x86_64-darwin14] 进行的。

【讨论】:

  • 它并没有真正回答我的问题。我的问题是为什么 Ruby 的简单插入排序实现比 JavaScript 中的类似实现慢得多。因此,将 Ruby 与 OS 实用程序进行比较是不恰当的。也许在 JS 中编写快速排序,然后与 Ruby 实现进行比较可以提供一些线索。
  • 我不同意。您的要求要求我们假设一大堆事情是相似的,包括您对排序算法的实现、解释器使用的行为、构建的优化、在构建 ruby​​ 和 JS 期间对内部库和系统库的依赖口译员等。
  • (对不起,一个学生来上班。)你的经验不支持 Ruby 作为一门语言本质上很慢的论点 - 我已经给出了一个反例来说明其他情况。实际上,我很惊讶解释语言可以在系统实用程序的一个数量级内实现运行时间。对我来说,这表明问题可能是实现问题之一,可能在您系统的语言端口中,可能是因为尝试从一种语言逐字翻译到另一种语言对计算机语言的效果并不比对人类语言更好。
  • 我从来没有说过 Ruby 是慢速语言 - 我说 Ruby 与 JavaScript 相比对于这个算法来说是慢的。我不要求对口译员的工作方式等进行假设。我只想知道为什么会这样。可能解释器优化或编程语言如何在内存中存储数组是答案,但我不知道 - 这就是我问这个问题的原因。
  • 如果是因为解释器优化,或者其他特定于您的安装的原因,其他人无法知道。
猜你喜欢
  • 1970-01-01
  • 2011-03-12
  • 1970-01-01
  • 2012-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多