5

我一直在考虑优化一个 ruby​​ 程序,该程序对大量数据的计算非常密集。我不懂 C 并且选择了 Ruby(我也不是很了解它),而且我对结果非常满意,除了执行所需的时间。这是很多数据,而且不花任何钱,我想知道我能做些什么来确保我最大限度地利用我自己的系统资源。

当我运行一个基本的 Ruby 程序时,它是否使用单个处理器?如果我没有专门为处理器分配任务,Ruby 不会读取我的程序并神奇地加载每个处理器以尽可能快地完成程序,对吗?我假设没有...

我一直在阅读一些关于加速 Ruby 的文章,并且在另一个线程中读到 Ruby 不支持真正的多线程(尽管它说 JRuby 支持)。但是,如果我将我的程序“分解”成两个可以在单独实例中运行的块并以并行方式运行它们......这两个块会自动在两个单独的处理器上运行吗?如果我有四个处理器并打开四个外壳并运行程序的四个独立部分(1/4) - 它会在 1/4 的时间内完成吗?

更新

阅读评论后,我决定试一试 JRuby。移植应用程序并不是那么困难。我还没有使用过“peach”,但只要在 JRuby 中运行它,应用程序就可以运行 1/4 的时间!!!疯狂的。我没想到会有这么大的变化。现在要给 .peach 一个机会,看看它是如何改进的。仍然无法相信这种提升。

更新#2

刚刚试了一下桃子。最终节省了 15% 的时间。所以切换到 JRuby 并使用 Peach 绝对值得。

谢谢大家!

4

4 回答 4

4

使用 JRuby 和peach gem,再简单不过了。只需替换一个.eachwith.peach和瞧,您正在并行执行。还有其他选项可以准确控制产生了多少线程等。我已经使用了它,效果很好。

您将获得接近n倍的加速,其中n是可用的 CPU/内核数。我发现最佳线程数略多于 CPU/内核数。

于 2012-11-12T22:50:23.800 回答
2

就像其他人所说的 ruby​​(大多数人使用的)的 MRI 实现不支持本机线程。因此,您不能通过使用 MRI 实现启动更多线程来在 CPU 内核之间分配工作。

但是,如果您的进程是 IO 绑定的(例如受磁盘或网络活动限制),那么您仍然可以从多个 MRI 线程中受益。

另一方面,JRuby 确实支持本机线程,这意味着您可以使用线程在 CPU 内核之间拆分工作。

但一切都没有丢失。使用 MRI(以及所有其他 ruby​​ 实现),您仍然可以使用进程来拆分工作。

这可以使用Process.fork例如这样的方式来完成:

Process.fork {
  10.times {
    # Do some work in process 1
    sleep 1
    puts "Hello 1"
  }
}

Process.fork {
  10.times {
    # Do some work in process 2
    sleep 1
    puts "Hello 2"
  }
}

# Wait for the child processes to finish
Process.wait

使用fork将在 CPU 内核之间拆分处理,因此如果您可以在没有线程的情况下生活,那么单独的进程是一种方法。

于 2012-11-12T20:14:42.687 回答
0

线程通常被认为是 Ruby 的弱点之一,但它更多地取决于您使用的 Ruby 实现。

关于不同线程模型的一篇非常好的文章是“ Ruby 有真正的多线程吗? ”。

根据我的经验以及从更了解这些东西的人那里收集到的信息,如果您要选择 Ruby 实现,JRuby 似乎是您的最佳选择。但是,如果您正在学习 Ruby,您可能想选择另一种语言,例如 Erlang,或者 Clojure,如果您想使用 JVM,这些都是流行的选择。

于 2012-11-12T20:03:37.297 回答
0

与 ruby​​ 一样好,它的执行速度并不为人所知。话虽如此,如果如您的评论中所述,您可以将输入分成大小相等的块,您应该能够启动程序的 n 个实例,其中 n 是您拥有的内核数,并且操作系统将照顾你使用所有的核心。

在最好的情况下,它会以 1/n 的时间运行,但是这种事情可能很难完全正确,因为系统的某些部分,比如内存,需要在进程之间共享,并且进程之间的争用可能会导致问题不要线性缩放。如果拆分很容易,我会尝试一下。您也可以尝试运行相同的程序两次,看看运行需要多长时间,如果运行一个程序所需的时间与运行两个程序所需的时间相同,那么您可能已经准备好了,只需拆分数据并继续它。

尝试 jruby 和一些线程可能会有所帮助,但这会增加相当多的复杂性。(这可能是学习线程的一个很好的借口。)

于 2012-11-12T20:09:55.180 回答