为了账号安全,请及时绑定邮箱和手机立即绑定

ruby有真正的多线程吗?

/ 猿问

ruby有真正的多线程吗?

qq_遁去的一_1 2019-08-09 10:44:05

ruby有真正的多线程吗?

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



查看完整描述

3 回答

?
慕娘9325324

你似乎混淆了两个非常这里不同的东西: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


查看完整回答
反对 回复 2019-08-09
?
狐的传说

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

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


查看完整回答
反对 回复 2019-08-09
?
蝴蝶不菲

这取决于实施: 

  • MRI没有,YARV更接近。

  • JRuby和MacRuby有。




Ruby有倒闭BlockslambdasProcs。为了充分利用JRuby中的闭包和多核,Java的执行器就派上用场了; 对于MacRuby我喜欢GCD的队列。 

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

这是使用Ruby 2.1.0 使用3个线程的简单Ruby程序的输出:

(jalcazar@mac ~)$ ps -M 69877USER     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 72286USER     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 38293USER     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


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

(jalcazar@mac ~)$ ps -M 70032USER     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线程不能并行运行。


查看完整回答
反对 回复 2019-08-09
  • 3 回答
  • 0 关注
  • 133 浏览
我要回答

相关问题推荐

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信