我知道ruby使用green threads的“协作”线程。如何在应用程序中创建真实的的“操作系统级”线程,以便利用多个cpu内核进行处理?
q3aa05251#
更新了Jörg 2011年9月的评论
你似乎混淆了两个 * 非常 * 不同的事情:Ruby编程语言和Ruby编程语言的一个特定实现的特定线程模型。目前大约有11种不同的Ruby编程语言实现,它们具有 * 非常 * 不同和独特的线程模型。(不幸的是,这11个实现中只有两个实际上可以用于生产,但到今年年底,这个数字可能会增加到4或5个。现在是5:MRI、JRuby、YARV(Ruby 1.9的解释器)、Rubinius和IronRuby)。1.第一个实现实际上没有名称,这使得引用它非常尴尬,并且非常烦人和令人困惑。它通常被称为“Ruby”,这比没有名字更令人讨厌和困惑,因为它导致Ruby编程语言的功能和特定的Ruby实现之间的无休止的混淆。它有时也被称为“MRI”(“Matz的Ruby实现”),CRuby或MatzRuby。不幸的是,它不允许并行调度这些线程,它们一次只能运行一个线程。但是,任何数量的C线程(POSIX线程等)都可以与Ruby线程并行运行,因此外部C库或创建自己线程的MRI C扩展仍然可以并行运行。1.第二个实现是YARV(Yet Another Ruby VM的缩写)。YARV implements Ruby Threads as POSIX or Windows NT Threads,但是,它使用全局解释器锁(GIL)来确保在任何时候实际上只能调度一个Ruby线程。像MRI一样,C线程实际上可以与Ruby线程并行运行。在未来,GIL * 可能 * 会被分解为更细粒度的锁,从而允许越来越多的代码实际并行运行,但这是如此遥远,甚至还没有 * 计划 *。
更新:本答案中有关Rubinius的信息是关于Shotgun VM的,该VM已不存在。“新的”C++ VM不使用跨多个VM调度的绿色线程(即Erlang/BEAM风格),它使用了一个更传统的单VM和多个本机OS线程模型,就像CLR、Mono和几乎所有JVM所使用的模型一样。
MacRuby最初是YARV的一个端口,位于Objective-C Runtime、CoreFoundation和可可Frameworks之上。它现在与YARV有很大的不同,但AFAIK目前仍然是shares the same Threading Model with YARV。**更新:**MacRuby依赖于苹果的垃圾收集器,该垃圾收集器已被宣布弃用,并将在MacOSX的后续版本中删除,MacRuby是不死的。
Cardinal是Parrot Virtual Machine的Ruby实现。它还没有实现线程,但是,当它实现线程时,它可能会将它们实现为Parrot Threads。更新:红衣主教似乎很不活跃/死了。
MagLev是GemStone/S Smalltalk VM的Ruby实现。我不知道GemStone/S使用什么线程模型,MagLev使用什么线程模型,甚至还没有实现线程(可能没有)。
HotRuby不是一个完整的Ruby实现。它是JavaScript中YARV字节码VM的实现。HotRuby不支持线程(还没有?)),当它这样做时,它们将无法并行运行,因为JavaScript不支持真正的并行性。不过,有一个ActionScript版本的HotRuby,而且ActionScript实际上可能支持并行性。更新:HotRuby死了不幸的是,这11个Ruby实现中只有两个实际上是生产就绪的:MRI和JRuby。所以,如果你想要真正的并行线程,JRuby是目前唯一的选择--并不是说这是一个糟糕的选择:JRuby实际上比MRI更快,而且可以说更稳定。否则,“经典”Ruby解决方案是使用进程而不是线程来实现并行性。Ruby Core Library包含Process module和Process.fork方法,这使得派生另一个Ruby进程变得非常容易。此外,Ruby标准库包含Distributed Ruby (dRuby / dRb)库,它允许Ruby代码在多个进程中进行简单的分发,不仅在同一台机器上,而且在网络上。
Process
Process.fork
h9a6wy2h2#
Ruby 1.8只有绿色线程,没有办法创建真实的的“OS级”线程。但是,ruby1.9将有一个名为fibers的新特性,它将允许您创建实际的操作系统级线程。不幸的是,Ruby 1.9仍处于beta阶段,预计在几个月内稳定。另一种选择是使用JRuby。JRuby将线程实现为操作系统级头,其中没有“绿色线程”。JRuby的最新版本是1.1.4,相当于Ruby1.8
cyej8jka3#
这取决于实现:
Ruby有closures,Blocks,lambdas和Procs。为了充分利用JRuby中的闭包和多核,Java's executors派上了用场;我喜欢GCD's queues。请注意,能够创建 * 真实的的“操作系统级”线程 * 并不意味着您可以使用多个cpu内核进行并行处理。请看下面的例子。下面是a simple Ruby program which uses 3 threads使用Ruby 2.1.0的输出:
Blocks
lambdas
Procs
(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
正如您在这里看到的,有四个OS线程,但是只有状态为R的线程正在运行。这是由于Ruby线程实现方式的限制。同样的程序,现在使用JRuby。您可以看到状态为R的三个线程,这意味着它们正在并行运行。
R
(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
同样的程序,现在用MacRuby。还有三个线程并行运行。这是因为MacRuby线程是POSIX线程(* 真实的的“操作系统级”线程 *),并且没有GVL
(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
再一次,同样的程序,但现在用的是老式的核磁共振成像。由于这个实现使用绿色线程,所以只显示一个线程
(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
如果你对Ruby多线程感兴趣,你可能会发现我的报告 * Debugging parallel programs using fork handlers * 很有趣。关于Ruby内部的更一般的概述 * Ruby Under a Microscope * 是一个很好的阅读。此外,Omniref中的Ruby线程和C中的全局解释器锁在源代码中解释了为什么Ruby线程不能并行运行。
hjqgdpho4#
如何使用drb?它不是真实的的多线程,而是多个进程之间的通信,但你现在可以在1.8中使用它,而且它的摩擦相当低。
envsm3lx5#
我会让“系统监视器”回答这个问题。在这两种情况下,我都在i7(4个超线程内核)机器上运行8个Ruby线程来执行相同的代码(下面,它计算素数)。第一次运行是:jruby 1.5.6(ruby 1.8.7 patchlevel 249)(2014-02-03 6586)(OpenJDK 64-Bit Server 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(没有超线程?)
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
ryoqjall6#
如果您使用MRI,那么您可以使用C编写线程代码,作为扩展或使用ruby-inline gem。
tnkciper7#
如果你真的需要Ruby中的并行性用于生产级别的系统(你不能使用beta),进程可能是一个更好的选择。但是,首先在JRuby下尝试线程绝对值得。另外,如果你对Ruby下的线程未来感兴趣,你可能会发现这个article很有用。
enxuqcxy8#
以下是关于Rinda的一些信息,它是琳达(并行处理和分布式计算范例)http://charmalloc.blogspot.com/2009/12/linda-tuples-rinda-drb-parallel.html的Ruby实现
xn1cxnb49#
因为无法编辑该答案,所以在此处添加新的回复。
更新(2017-05-08)
这篇文章很旧了,信息不符合当前(2017)的趋势,以下是一些补充:
9条答案
按热度按时间q3aa05251#
更新了Jörg 2011年9月的评论
你似乎混淆了两个 * 非常 * 不同的事情:Ruby编程语言和Ruby编程语言的一个特定实现的特定线程模型。目前大约有11种不同的Ruby编程语言实现,它们具有 * 非常 * 不同和独特的线程模型。
(不幸的是,这11个实现中只有两个实际上可以用于生产,但到今年年底,这个数字可能会增加到4或5个。现在是5:MRI、JRuby、YARV(Ruby 1.9的解释器)、Rubinius和IronRuby)。
1.第一个实现实际上没有名称,这使得引用它非常尴尬,并且非常烦人和令人困惑。它通常被称为“Ruby”,这比没有名字更令人讨厌和困惑,因为它导致Ruby编程语言的功能和特定的Ruby实现之间的无休止的混淆。
它有时也被称为“MRI”(“Matz的Ruby实现”),CRuby或MatzRuby。
不幸的是,它不允许并行调度这些线程,它们一次只能运行一个线程。
但是,任何数量的C线程(POSIX线程等)都可以与Ruby线程并行运行,因此外部C库或创建自己线程的MRI C扩展仍然可以并行运行。
1.第二个实现是YARV(Yet Another Ruby VM的缩写)。YARV implements Ruby Threads as POSIX or Windows NT Threads,但是,它使用全局解释器锁(GIL)来确保在任何时候实际上只能调度一个Ruby线程。
像MRI一样,C线程实际上可以与Ruby线程并行运行。
在未来,GIL * 可能 * 会被分解为更细粒度的锁,从而允许越来越多的代码实际并行运行,但这是如此遥远,甚至还没有 * 计划 *。
Rubinius目前无法并行调度线程,不过,这并不是一个太大的问题:Rubinius已经可以在一个Rubinius进程中在多个POSIX线程中并行运行多个VM示例。由于线程实际上是在Ruby中实现的,因此它们可以像任何其他Ruby对象一样被序列化并发送到不同POSIX线程中的不同VM。(这与BEAM Erlang VM用于SMP并发的模型相同。已经是implemented for Rubinius Actors了。)
更新:本答案中有关Rubinius的信息是关于Shotgun VM的,该VM已不存在。“新的”C++ VM不使用跨多个VM调度的绿色线程(即Erlang/BEAM风格),它使用了一个更传统的单VM和多个本机OS线程模型,就像CLR、Mono和几乎所有JVM所使用的模型一样。
MacRuby最初是YARV的一个端口,位于Objective-C Runtime、CoreFoundation和可可Frameworks之上。它现在与YARV有很大的不同,但AFAIK目前仍然是shares the same Threading Model with YARV。**更新:**MacRuby依赖于苹果的垃圾收集器,该垃圾收集器已被宣布弃用,并将在MacOSX的后续版本中删除,MacRuby是不死的。
Cardinal是Parrot Virtual Machine的Ruby实现。它还没有实现线程,但是,当它实现线程时,它可能会将它们实现为Parrot Threads。更新:红衣主教似乎很不活跃/死了。
MagLev是GemStone/S Smalltalk VM的Ruby实现。我不知道GemStone/S使用什么线程模型,MagLev使用什么线程模型,甚至还没有实现线程(可能没有)。
HotRuby不是一个完整的Ruby实现。它是JavaScript中YARV字节码VM的实现。HotRuby不支持线程(还没有?)),当它这样做时,它们将无法并行运行,因为JavaScript不支持真正的并行性。不过,有一个ActionScript版本的HotRuby,而且ActionScript实际上可能支持并行性。更新:HotRuby死了
不幸的是,这11个Ruby实现中只有两个实际上是生产就绪的:MRI和JRuby。
所以,如果你想要真正的并行线程,JRuby是目前唯一的选择--并不是说这是一个糟糕的选择:JRuby实际上比MRI更快,而且可以说更稳定。
否则,“经典”Ruby解决方案是使用进程而不是线程来实现并行性。Ruby Core Library包含
Process
module和Process.fork
方法,这使得派生另一个Ruby进程变得非常容易。此外,Ruby标准库包含Distributed Ruby (dRuby / dRb)库,它允许Ruby代码在多个进程中进行简单的分发,不仅在同一台机器上,而且在网络上。h9a6wy2h2#
Ruby 1.8只有绿色线程,没有办法创建真实的的“OS级”线程。但是,ruby1.9将有一个名为fibers的新特性,它将允许您创建实际的操作系统级线程。不幸的是,Ruby 1.9仍处于beta阶段,预计在几个月内稳定。
另一种选择是使用JRuby。JRuby将线程实现为操作系统级头,其中没有“绿色线程”。JRuby的最新版本是1.1.4,相当于Ruby1.8
cyej8jka3#
这取决于实现:
Ruby有closures,
Blocks
,lambdas
和Procs
。为了充分利用JRuby中的闭包和多核,Java's executors派上了用场;我喜欢GCD's queues。请注意,能够创建 * 真实的的“操作系统级”线程 * 并不意味着您可以使用多个cpu内核进行并行处理。请看下面的例子。
下面是a simple Ruby program which uses 3 threads使用Ruby 2.1.0的输出:
正如您在这里看到的,有四个OS线程,但是只有状态为
R
的线程正在运行。这是由于Ruby线程实现方式的限制。同样的程序,现在使用JRuby。您可以看到状态为
R
的三个线程,这意味着它们正在并行运行。同样的程序,现在用MacRuby。还有三个线程并行运行。这是因为MacRuby线程是POSIX线程(* 真实的的“操作系统级”线程 *),并且没有GVL
再一次,同样的程序,但现在用的是老式的核磁共振成像。由于这个实现使用绿色线程,所以只显示一个线程
如果你对Ruby多线程感兴趣,你可能会发现我的报告 * Debugging parallel programs using fork handlers * 很有趣。
关于Ruby内部的更一般的概述 * Ruby Under a Microscope * 是一个很好的阅读。
此外,Omniref中的Ruby线程和C中的全局解释器锁在源代码中解释了为什么Ruby线程不能并行运行。
hjqgdpho4#
如何使用drb?它不是真实的的多线程,而是多个进程之间的通信,但你现在可以在1.8中使用它,而且它的摩擦相当低。
envsm3lx5#
我会让“系统监视器”回答这个问题。在这两种情况下,我都在i7(4个超线程内核)机器上运行8个Ruby线程来执行相同的代码(下面,它计算素数)。第一次运行是:
jruby 1.5.6(ruby 1.8.7 patchlevel 249)(2014-02-03 6586)(OpenJDK 64-Bit Server 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(没有超线程?)
ryoqjall6#
如果您使用MRI,那么您可以使用C编写线程代码,作为扩展或使用ruby-inline gem。
tnkciper7#
如果你真的需要Ruby中的并行性用于生产级别的系统(你不能使用beta),进程可能是一个更好的选择。
但是,首先在JRuby下尝试线程绝对值得。
另外,如果你对Ruby下的线程未来感兴趣,你可能会发现这个article很有用。
enxuqcxy8#
以下是关于Rinda的一些信息,它是琳达(并行处理和分布式计算范例)http://charmalloc.blogspot.com/2009/12/linda-tuples-rinda-drb-parallel.html的Ruby实现
xn1cxnb49#
因为无法编辑该答案,所以在此处添加新的回复。
更新(2017-05-08)
这篇文章很旧了,信息不符合当前(2017)的趋势,以下是一些补充: