我一直在考虑优化一个对大量数据进行计算密集的ruby程序。我不知道C并且选择了Ruby(不是我也很清楚)并且我对结果非常满意,除了执行它所花费的时间。这是一个很多数据,没有花任何钱,我想知道我能做些什么来确保我最大化自己的系统资源。
当我运行基本的Ruby程序时,它是否使用单个处理器?如果我没有专门为处理器分配任务,Ruby将无法读取我的程序并神奇地加载每个处理器以尽快完成程序吗?我假设没有......
我一直在阅读关于加速Ruby的一些内容,并在另一个线程中读到Ruby不支持真正的多线程(虽然它说JRuby确实如此)。但是,如果我将我的程序“分解”为两个可以在不同实例中运行的块并以parralel运行它们......这两个块会自动在两个独立的处理器上运行吗?如果我有四个处理器并打开了四个炮弹并运行了四个独立的部分(1/4) - 它会在1/4的时间内完成吗?
在阅读评论后,我决定给JRuby一个机会。移植应用程序并不困难。我还没有使用“桃子”,但只需在JRuby中运行它,该应用程序运行时间为1/4!疯。我没想到会发生太大变化。现在给.peach打一针,看看它是如何改善的。仍然无法相信提升。
试试桃子吧。结束剃须另外15%的时间。所以切换到JRuby并使用Peach绝对是值得的。
谢谢大家!
答案 0 :(得分:4)
使用JRuby和peach gem,这可能不容易。只需将.each
替换为.peach
,即可并行执行。并且还有其他选项可以精确控制生成的线程数等等。我已经使用过它并且效果很好。
您接近 n 次加速,其中 n 是可用的CPU /核心数。我发现最佳线程数略多于CPU /核心数。
答案 1 :(得分: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内核之间的处理,因此如果您可以在没有线程的情况下生存,那么单独的进程就是一种方法。
答案 2 :(得分:0)
线程通常被认为是Ruby的弱点之一,但它更多地取决于您使用的Ruby实现。
对不同线程模型的一个非常好的写法是“Does ruby have real multithreading?”。
从我的经验和我从那些对这些东西了解得更好的人那里收集的内容来看,如果你要选择一个Ruby实现,JRuby就是你要走的路。但是,如果你正在学习Ruby,你可能想要选择另一种语言,如Erlang,或者Clojure,如果你想使用JVM,它们是很受欢迎的选择。
答案 3 :(得分:0)
和红宝石一样好,它的执行速度并不为人所知。话虽这么说,如果你在评论中指出,你可以将输入分解为相等大小的块,你应该能够启动程序的n个实例,其中n是你拥有的核心数,操作系统将为您使用所有核心。
在最好的情况下,它会在1 / n的时间运行,但是这样的事情可能很难完全正确,因为系统的某些部分(如内存)需要在进程之间共享和进程之间的争用可能导致事物不能线性扩展。如果拆分很容易,我试一试。您也可以尝试两次运行相同的程序,看看运行需要多长时间,如果运行一次需要相同的时间,那么运行两次就可能全部设置,只需拆分数据并转到它。
尝试jruby和一些线程可能会有所帮助,但这会增加相当大的复杂性。 (这可能是了解线程的一个很好的借口。)