我知道使用绿色线程的ruby的"合作" 线程.如何在我的应用程序中创建真正的"操作系统级"线程,以便使用多个cpu内核进行处理?
更新了Jörg的2011年9月评论
你似乎混淆了两个非常这里不同的东西:Ruby编程语言和一个具体实施Ruby编程语言的特定线程模型.目前有大约11种不同的Ruby编程语言实现,具有非常不同且独特的线程模型.
(不幸的是,这11个实现中只有两个实际上已准备好用于生产,但到年底这个数字可能会达到四个或五个.)(更新:它现在是5:MRI,JRuby,YARV(解释器)对于Ruby 1.9),Rubinius和IronRuby).
第一个实现实际上没有名称,这使得引用它非常尴尬,并且真的很烦人和令人困惑.它通常被称为"Ruby",它比没有名称更令人讨厌和混乱,因为它导致Ruby编程语言的特性和特定的Ruby实现之间的无休止的混淆.
它有时也被称为"MRI"(用于"Matz的Ruby实现"),CRuby或MatzRuby.
MRI在其解释器中将Ruby Threads实现为绿色线程.不幸的是,它不允许并行调度这些线程,它们一次只能运行一个线程.
但是,任何数量的C线程(POSIX线程等)都可以与Ruby线程并行运行,因此创建自己的线程的外部C库或MRI C Extensions仍然可以并行运行.
第二个实现是YARV("又一个Ruby VM"的缩写).YARV将Ruby Threads实现为POSIX或Windows NT线程,但是,它使用全局解释器锁(GIL)来确保一次只能实际调度一个Ruby线程.
MRI一样,C线程可实际上到Ruby线程并行运行.
将来,有可能GIL 可能被分解为更细粒度的锁,从而允许越来越多的代码实际并行运行,但是这个目前还远,它甚至还没有计划好.
JRuby将 Ruby Threads实现为Native Threads,其中"Native Threads"在JVM的情况下显然意味着"JVM Threads".JRuby没有对它们施加额外的锁定.因此,这些线程是否可以实际并行运行取决于JVM:一些JVM将JVM线程实现为OS线程,一些实现为绿色线程.(自JDK 1.3起,Sun/Oracle的主流JVM专门使用OS线程)
XRuby还将Ruby Threads实现为JVM线程.更新:XRuby死了.
IronRuby将 Ruby Threads实现为Native Threads,其中CLR的"Native Threads"显然意味着"CLR Threads".IronRuby不对它们施加额外的锁定,因此,只要您的CLR支持它,它们就应该并行运行.
Ruby.NET还将Ruby Threads实现为CLR线程.更新: Ruby.NET已经死了.
Rubinius 在其虚拟机中将Ruby Threads实现为绿色线程.更确切地说:Rubinius VM导出一个非常轻量级,非常灵活的并发/并行/非本地控制流构造,称为" 任务 ",以及所有其他并发构造(本讨论中的线程,还有Continuations,Actors和其他东西) )使用Tasks在纯Ruby中实现.
Rubinius不能(当前)并行调度线程,但是,添加这并不是一个问题:Rubinius已经可以在一个Rubinius进程中并行运行多个POSIX线程中的多个VM实例.由于Threads实际上是在Ruby中实现的,因此它们可以像任何其他Ruby对象一样被序列化并发送到不同POSIX线程中的不同VM.(这与BEAM Erlang VM用于SMP并发的模型相同.它已经为Rubinius Actors实现.)
更新:在这个答案中关于Rubinius的信息是关于Shotgun VM,它不再存在."新"C++ VM不使用跨多个VM调度的绿色线程(即Erlang/BEAM样式),它使用具有多个本机OS线程模型的更传统的单个VM,就像CLR,Mono所采用的那样. ,几乎每个JVM.
MacRuby最初是在Objective-C Runtime和CoreFoundation以及Cocoa框架之上的YARV端口.它现在与YARV显着不同,但AFAIK目前仍然与YARV共享相同的线程模型. 更新: MacRuby依赖于苹果垃圾收集器,它被声明为已弃用,将在MacOSX的更高版本中删除,MacRuby是不死的.
Cardinal是Parrot虚拟机的Ruby实现.它还没有实现线程,但是,当它执行时,它可能会将它们实现为Parrot线程.更新:红衣主教似乎非常不活跃/死亡.
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
模块,这使得很容易分离出另一个Ruby进程.此外,Ruby标准库包含
分布式Ruby(dRuby/dRb)库,它允许Ruby代码轻松地分布在多个进程中,不仅在同一台机器上,而且在整个网络中.Process.fork
Ruby 1.8只有绿色线程,没有办法创建一个真正的"操作系统级"线程.但是,ruby 1.9将有一个名为fiber的新功能,它将允许您创建实际的操作系统级线程.不幸的是,Ruby 1.9仍然处于测试阶段,计划在几个月后保持稳定.
另一种选择是使用JRuby.JRuby将线程实现为OS级别的theads,其中没有"绿色线程".JRuby的最新版本是1.1.4,相当于Ruby 1.8
这取决于实施:
RMI没有,YARV更接近.
JRuby和MacRuby有.
Ruby有倒闭的Blocks
,lambdas
和Procs
.为了充分利用JRuby中的闭包和多核,Java的执行器就派上用场了; 对于MacRuby我喜欢GCD的队列.
请注意,能够创建真正的"OS级"线程并不意味着您可以使用多个cpu内核进行并行处理.请看下面的例子.
这是使用Ruby 2.1.0 使用3个线程的简单Ruby程序的输出:
(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
,这意味着它们并行运行.
(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线程(真正的"OS级"线程)并且没有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
再次,相同的程序,但现在与良好的旧RMI.由于此实现使用绿色线程,因此只显示一个线程
(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多线程感兴趣,可能会发现我的报告使用fork处理程序调试并行程序很有趣.
有关Ruby内部的更一般概述Ruby Under a Microscope是一本很好的读物.
此外,Ruby Threads和 Omniref 中的C语言全局解释器锁在源代码中解释了为什么Ruby线程不能并行运行.