ruby有真正的多线程吗?

时间:2008-09-11 09:01:36

标签: ruby multithreading concurrency

我知道使用green threads的ruby“合作”线程。如何在我的应用程序中创建真正的“操作系统级”线程,以便利用多个cpu内核进行处理?

8 个答案:

答案 0 :(得分:599)

答案 1 :(得分:28)

Ruby 1.8只有绿色线程,没有办法创建一个真正的“操作系统级”线程。但是,ruby 1.9将有一个名为fiber的新功能,它将允许您创建实际的操作系统级线程。不幸的是,Ruby 1.9仍处于测试阶段,计划在几个月内保持稳定。

另一种选择是使用JRuby。 JRuby将线程实现为OS级别的theads,其中没有“绿色线程”。 JRuby的最新版本是1.1.4,相当于Ruby 1.8

答案 2 :(得分:8)

这取决于实施:

  • MRI没有,YARV更接近。
  • JRuby和MacRuby有。




Ruby BlockslambdasProcs(jalcazar@mac ~)$ ps -M 69877 USER PID TT %CPU STAT PRI STIME UTIME COMMAND jalcazar 69877 s002 0.0 S 31T 0:00.01 0:00.04 /Users/jalcazar/.rvm/rubies/ruby-2.1.0/bin/ruby threads.rb 69877 0.0 S 31T 0:00.01 0:00.00 69877 33.4 S 31T 0:00.01 0:08.73 69877 43.1 S 31T 0:00.01 0:08.73 69877 22.8 R 31T 0:00.01 0:08.65 。为了充分利用JRuby中的闭包和多核,closures派上用场;对于MacRuby,我喜欢Java's executors

请注意,能够创建真正的“操作系统级”线程并不意味着您可以使用多个cpu内核进行并行处理。请看下面的例子。

这是使用Ruby 2.1.0的GCD's queues的输出:

R

正如您在此处所见,有四个操作系统线程,但只有状态为R的操作系统正在运行。这是因为Ruby的线程实现方式存在限制。



相同的程序,现在与JRuby。您可以看到状态为(jalcazar@mac ~)$ ps -M 72286 USER PID TT %CPU STAT PRI STIME UTIME COMMAND jalcazar 72286 s002 0.0 S 31T 0:00.01 0:00.01 /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home/bin/java -Djdk.home= -Djruby.home=/Users/jalcazar/.rvm/rubies/jruby-1.7.10 -Djruby.script=jruby -Djruby.shell=/bin/sh -Djffi.boot.library.path=/Users/jalcazar/.rvm/rubies/jruby-1.7.10/lib/jni:/Users/jalcazar/.rvm/rubies/jruby-1.7.10/lib/jni/Darwin -Xss2048k -Dsun.java.command=org.jruby.Main -cp -Xbootclasspath/a:/Users/jalcazar/.rvm/rubies/jruby-1.7.10/lib/jruby.jar -Xmx1924M -XX:PermSize=992m -Dfile.encoding=UTF-8 org/jruby/Main threads.rb 72286 0.0 S 31T 0:00.00 0:00.00 72286 0.0 S 33T 0:00.00 0:00.00 72286 0.0 S 31T 0:00.09 0:02.34 72286 7.9 S 31T 0:00.15 0:04.63 72286 0.0 S 31T 0:00.00 0:00.00 72286 0.0 S 31T 0:00.00 0:00.00 72286 0.0 S 31T 0:00.00 0:00.00 72286 0.0 S 31T 0:00.04 0:01.68 72286 0.0 S 31T 0:00.03 0:01.54 72286 0.0 S 31T 0:00.00 0:00.00 72286 0.0 S 31T 0:00.01 0:00.01 72286 0.0 S 31T 0:00.00 0:00.01 72286 0.0 S 31T 0:00.00 0:00.03 72286 74.2 R 31T 0:09.21 0:37.73 72286 72.4 R 31T 0:09.24 0:37.71 72286 74.7 R 31T 0:09.24 0:37.80 的三个线程,这意味着它们并行运行。

(jalcazar@mac ~)$ ps -M 38293
USER     PID   TT   %CPU STAT PRI     STIME     UTIME COMMAND
jalcazar 38293 s002    0.0 R     0T   0:00.02   0:00.10 /Users/jalcazar/.rvm/rubies/macruby-0.12/usr/bin/macruby threads.rb
   38293         0.0 S    33T   0:00.00   0:00.00 
   38293       100.0 R    31T   0:00.04   0:21.92 
   38293       100.0 R    31T   0:00.04   0:21.95 
   38293       100.0 R    31T   0:00.04   0:21.99 


同样的程序,现在与MacRuby。还有三个并行运行的线程。这是因为a simple Ruby program which uses 3 threads真正的“操作系统级”线程)并且有MacRuby threads are POSIX threads

(jalcazar@mac ~)$ ps -M 70032
USER     PID   TT   %CPU STAT PRI     STIME     UTIME COMMAND
jalcazar 70032 s002  100.0 R    31T   0:00.08   0:26.62 /Users/jalcazar/.rvm/rubies/ruby-1.8.7-p374/bin/ruby threads.rb


再次,相同的程序,但现在与良好的旧MRI。由于此实现使用绿色线程,因此只显示一个线程

{{1}}



如果您对Ruby多线程感兴趣,可能会发现我的报告 no GVL 很有趣。
有关Ruby内部的更一般概述 Debugging parallel programs using fork handlers 是一个很好的阅读。
此外,Omniref中的Ruby Under a Microscope在源代码中解释了为什么Ruby线程不能并行运行。

答案 3 :(得分:4)

如何使用drb?这不是真正的多线程,而是几个进程之间的通信,但你现在可以在1.8中使用它并且它的摩擦力相当低。

答案 4 :(得分:3)

我会让"系统监视器"回答这个问题。我执行相同的代码(下面,计算素数),在两种情况下都运行在i7(4超线程核心)机器上的8个Ruby线程......第一次运行是:

jruby 1.5.6(ruby 1.8.7 patchlevel 249)(2014-02-03 6586) (OpenJDK 64位服务器VM 1.7.0_75)[amd64-java]

第二个是:

ruby​​ 2.1.2p95(2014-05-08)[x86_64-linux-gnu]

有趣的是,JRuby线程的CPU更高,但解释Ruby的完成时间略短。从图中可以很难说出来,但第二个(解释后的Ruby)运行使用大约1/2的CPU(没有超线程?)

enter image description here

def eratosthenes(n)
  nums = [nil, nil, *2..n]
  (2..Math.sqrt(n)).each do |i|
    (i**2..n).step(i){|m| nums[m] = nil}  if nums[i]
  end
  nums.compact
end

MAX_PRIME=10000000
THREADS=8
threads = []

1.upto(THREADS) do |num|
  puts "Starting thread #{num}"
  threads[num]=Thread.new { eratosthenes MAX_PRIME }
end

1.upto(THREADS) do |num|
    threads[num].join
end

答案 5 :(得分:1)

如果您正在使用MRI,那么您可以将C中的线程代码作为扩展名或使用ruby-inline gem编写。

答案 6 :(得分:1)

如果你真的需要在Ruby中实现生产级系统的并行性(你不能使用beta),那么进程可能是更好的选择。
但是,首先肯定要在JRuby下尝试线程。

此外,如果您对Ruby下的线程未来感兴趣,您可能会发现这个article很有用。

答案 7 :(得分:1)

以下是Rinda的一些信息,它是Linda的Ruby实现(并行处理和分布式计算范例)http://charmalloc.blogspot.com/2009/12/linda-tuples-rinda-drb-parallel.html