2008-09-11 59 views

回答

586

與約爾格的2011年9月評論

更新你似乎是令人費解!非常不同,這裏的東西: Ruby編程語言和一個 具體實施Ruby編程語言的特定線程模型。目前有 大約有11種不同的Ruby 編程語言的實現,其中有不同和唯一線程 模型。

(不幸的是,只有其中的兩個11所實現的實際上是 可供生產使用,但到今年年底,這個數字 將可能上升到四,五。)(更新:它現在是5: MRI,JRuby,YARV(Ruby 1.9的解釋器),Rubinius和IronRuby)。

  1. 首次實施實際上並沒有一個名字, 使得它比較尷尬提及它,實在是煩人和 混亂。它通常被稱爲「Ruby」,它甚至比沒有名字更令人討厭和困惑,因爲它會導致Ruby 編程語言和特定Ruby實現之間的無窮混淆。

    它有時也被稱爲「MRI」(對於「Matz's Ruby 實現」),CRuby或MatzRuby。

    MRI implements Ruby Threads as Green Threads within its interpreter。不幸的是,它不允許並行調度那些線程 ,它們只能在 時間運行一個線程。

    然而,任何編號C線程(POSIX線程等)可以運行在平行於Ruby的線程 ,所以外部C庫,或MRI C擴展,創造屬於自己的線程並行 仍然可以運行。

  2. 第二個實現是YARV(「Yet Another Ruby VM」的縮寫)。然而,它使用全局解釋器 鎖定(GIL)來確保在任何時候只有一個Ruby線程實際上可以被排列爲 。

    像MRI,C線程可以實際上平行於Ruby線程運行。

    在未來,它是可能的是,GIL 可能獲得破 分解成更細粒度鎖,從而使越來越多的 代碼實際並行運行,但這是那麼遙遠,它是 甚至沒有計劃呢。

  3. JRubyimplements Ruby Threads as Native Threads, 其中 「本地線程」 在JVM的情況下,顯然意味着 「JVM 線程」。 JRuby對它們沒有額外的鎖定。因此, 這些線程是否可以實際並行運行取決於JVM的 :某些JVM將JVM線程實現爲OS線程,並將一些 作爲綠色線程實現。 (Sun/Oracle的主流JVM使用自JDK 1.3以來的獨佔操作系統線程)

  4. XRubyimplements Ruby Threads as JVM Threads更新:XRuby已經死了。

  5. IronRubyimplements Ruby Threads as Native Threads, 其中 「本地線程」 在CLR的情況下顯然意味着 「CLR線程」。 IronRuby不會額外鎖定它們,因此,它們應該並行運行,只要您的CLR支持 即可。

  6. Ruby.NETimplements Ruby Threads as CLR Threads更新: Ruby.NET已經死亡。

  7. Rubiniusimplements Ruby Threads as Green Threads within its Virtual Machine。更準確地說是Rubinius的 VM出口非常輕,非常靈活 併發/並行/非本地控制流結構,稱爲 一個「Task」,和所有其他併發結構(版面中 這個討論,而且ContinuationsActors和 其他的東西)在純Ruby中使用任務來實現。

    Rubinius的不能(目前)調度線程並行, 然而,並稱不是太大的問題:Rubinius的可 已經run several VM instances in several POSIX Threads in parallel,一個Rubinius的過程內。由於線程實際上是在Ruby中實現的 ,因此它們可以像任何其他Ruby 對象一樣,被序列化併發送到不同的POSIX Thread中的VM。 (這與BEAM Erlang VM 用於SMP併發的模型相同。它已經是implemented for Rubinius Actors。)

    更新:關於Rubinius在這個答案的信息是關於Shotgun虛擬機,它不再存在。 「新」C++虛擬機不使用跨多個虛擬機調度的綠色線程(例如Erlang/BEAM風格),它使用更傳統的單一虛擬機和多種本地操作系統線程模型,就像CLR所使用的那樣,單聲道,幾乎每個JVM。

  8. MacRuby作爲YARV的一個端口,在 Objective-C運行時和CoreFoundation和Cocoa框架之上開始。它現在 已經明顯偏離了YARV,但是AFAIK它目前 仍然是shares the same Threading Model with YARV更新: MacRuby依賴於蘋果垃圾收集器,它已被宣佈不推薦使用,並將在更高版本的MacOSX中刪除,MacRuby不死。

  9. CardinalParrot Virtual Machine的Ruby實現。它還沒有實現線程,但是,當它這樣做時,它可能會將它們實現爲Parrot Threads更新:紅衣主教看起來非常不活躍/死亡。

  10. MagLevGemStone/S Smalltalk VM的Ruby實現。我不知道GemStone/S使用的線程模型 ,MagLev使用什麼線程模型,甚至線程甚至還未實現(可能不是)。

  11. HotRuby其 自己的完整的Ruby實現。它是一個在JavaScript中執行的YARV字節碼虛擬機。 HotRuby不支持線程(還有?),並且它在 做的時候,它們將不能並行運行,因爲JavaScript 不支持真正的並行。然而,HotRuby有一個ActionScript 版本,而ActionScript可能實際上支持並行性。 更新:HotRuby已死亡。

遺憾的是,只有其中兩個11所Ruby實現的是 實際生產就緒:MRI和JRuby。因此,如果你想要真正的並行線程,JRuby目前只是你的 唯一的選擇 - 這不是一個壞的選擇:JRuby實際上比MRI更快 ,並且可以說更穩定。

否則,「古典」Ruby解決方案是使用進程 而不是線程進行並行處理。紅寶石核心庫 包含Process moduleProcess.fork method,這使得它很容易分叉另一個紅寶石 過程。此外,Ruby標準庫包含 Distributed Ruby (dRuby/dRb)庫,該庫允許在多個進程間輕鬆地分佈代碼,而不僅僅在同一臺計算機上,而且在整個網絡上進行分佈式編程,而不僅僅是 。

25

Ruby 1.8只有綠色的線程,沒有辦法創建一個真正的「OS級」線​​程。但是,ruby 1.9將會有一個稱爲纖維的新功能,它可以讓你創建實際的OS級別的線程。不幸的是,Ruby 1.9仍處於測試階段,它計劃在幾個月內保持穩定。

另一種選擇是使用JRuby。 JRuby將線程實現爲OS級別的線程,其中沒有「綠色線程」。 JRuby的最新版本是1.1.4,相當於Ruby 1.8

+35

Ruby 1.8只有綠色線程是錯誤的,Ruby 1.8的幾個實現具有本機線程:JRuby,XRuby,Ruby.NET和IronRuby。 纖維不允許創建原生線程,它們比線程*更輕量。它們實際上是半協程,即它們是合作的。 – 2008-09-11 22:32:29

+18

我認爲從Josh的回答可以很明顯地看出,當他說Ruby 1.8時,他的意思是Ruby 1.8是運行時,也就是MRI,而不是Ruby 1.8。 – Theo 2011-04-22 19:46:18

4

如何使用drb?這不是真正的多線程,而是幾個進程之間的通信,但是現在可以在1.8版本中使用它,並且它的摩擦相當低。

1

如果您正在使用MRI,那麼您可以使用C語言編寫線程代碼作爲擴展名或使用ruby-inline gem。

1

如果您真的需要在Ruby中爲生產級別系統(不能使用測試版)進行並行化,那麼進程可能是更好的選擇。
但是,它絕對值得在JRuby下首先嚐試線程。

此外,如果您對Ruby下的線程未來感興趣,您可能會發現article有用。

+0

JRuby是一個不錯的選擇。對於使用進程的並行處理,我喜歡https://github.com/grosser/parallel`Parallel.map(['a','b','c'],:in_processes => 3){...' – user454322 2014-02-03 16:10:09

7

這取決於實現:

  • RMI沒有,YARV是接近。
  • JRuby和MacRuby都有。




Ruby有closuresBlockslambdasProcs。爲了充分利用JRuby中的閉包和多核,Java's executors派上用場;對於MacRuby我喜歡GCD's queues

請注意,能夠創建真正的「OS級」線​​程並不意味着您可以使用多個cpu核心進行並行處理。看下面的例子。

這是a simple Ruby program which uses 3 threads使用Ruby 2.1.0輸出:

([email protected] ~)$ 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 

正如你可以在這裏看到,有四個操作系統的線程,但是隻有一個與國家R運行。這是由於Ruby的線程被實現的限制。



同一個節目,現在使用JRuby。您可以看到三個狀態爲R的線程,這意味着它們並行運行。

([email protected] ~)$ 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 threads are POSIX threads真正的「操作系統級」線程),並有no GVL

([email protected] ~)$ 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。由於這個實現使用綠色線程的事實,只有一個線程顯示出來

([email protected] ~)$ 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 Threads and the Global Interpreter Lock in C在源代碼中解釋了爲什麼Ruby線程不能並行運行。

2

我會讓「系統監視器」回答這個問題。我正在執行相同的代碼(下面計算素數),在這兩種情況下,運行在i7(4超線程核心)機器上的8個Ruby線程......第一次運行是:

jruby 1.5.6 (紅寶石1.8.7 PATCHLEVEL 249)(2014年2月3日6586) (OpenJDK的64位服務器VM 1.7.0_75)AMD64的Java]

第二個是與:

紅寶石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 
0

因爲無法編輯答案,所以在這裏添加一個新的答覆。

更新(2017年5月8日)

這篇文章很老了,信息不遵循當前 (2017)胎面,以下是一些補充:

  • Opal是Ruby to JavaScript源到源編譯器。它還具有Ruby corelib的實現,它是當前非常活躍的開發工具,並且存在大量的(前端)框架。 和生產準備。因爲基於JavaScript,它不支持並行線程。

  • truffleruby是Ruby編程語言的高性能實現。 TrufleRuby由Oracle Labs構建於GraalVM上,是JRuby的一個分支,將其與Rubinius項目的代碼結合起來,還包含Ruby,MRI的標準實現代碼,仍然是實時開發,而不是生產準備。 這個版本的ruby好像天生就是性能,我不知道是否支持並行線程,但我認爲它應該。