Frage

Ich kenne das „kooperative“ Einfädeln von Ruby grüne Fäden.Wie kann ich in meiner Anwendung echte Threads auf „Betriebssystemebene“ erstellen, um mehrere CPU-Kerne für die Verarbeitung zu nutzen?

War es hilfreich?

Lösung

aktualisiert mit Jörgs September 2011 Kommentar

Sie scheinen zu sein verwirrend zwei sehr verschiedene Dinge hier: die Ruby-Programmiersprache und das spezifische Threading-Modell einer spezifische Implementierung der Programmiersprache Ruby. Dort Derzeit sind rund 11 verschiedene Implementierungen von Ruby Programmiersprache, mit sehr verschiedenem und einzigartigen Threading Modelle.

(Leider nur zwei dieser 11-Implementierungen sind eigentlich einsatzbereit für die Produktion, aber bis zum Ende des Jahres die Zahl geht bis zu vier oder fünf wahrscheinlich) ( Aktualisieren : es ist jetzt 5: MRT, JRuby, YARV (der Dolmetscher für Ruby 1.9).., Rubinius und IronRuby)

  1. Die erste Implementierung tatsächlich nicht über einen Namen, die macht es sehr umständlich, um es zu finden und ist wirklich ärgerlich und verwirrend. Es wird häufig als „Ruby“, die selbst ist ärgerlicher und verwirrend als keinen Namen hat, weil es führt zu endloser Verwirrung zwischen den Merkmalen des Rubins Programmiersprache und eine bestimmte Ruby-Implementierung.

    Es ist auch manchmal „MRI“ (für „Matz Ruby genannt Implementation "), CRuby oder MatzRuby.

    MRI implementiert Ruby-Threads als Green Threads innerhalb es ist Dolmetscher . Leider ist es nicht, diese Fäden erlauben parallel zu geplant werden, können sie nur bei einem ein Thread auszuführen Zeit.

    Jedoch kann eine beliebige Anzahl von C-Threads (POSIX Threads etc.) laufen parallel zum Ruby-Gewinde, so externe C-Bibliotheken oder MRI C-Erweiterungen, die Fäden ihrer eigenen erstellen können noch laufen in parallel.

  2. Die zweite Implementierung ist YARV (kurz für „Doch Ein anderer Ruby-VM "). YARV implementiert Ruby-Threads als POSIX oder Windows NT Threads jedoch verwendet es eine globale Interpreter Lock (GIL), um sicherzustellen, dass nur ein Ruby-Thread kann tatsächlich sein geplant zu einem beliebigen Zeitpunkt.

    Wie MRI, C Themen können laufen tatsächlich parallel zu Ruby-Threads.

    In der Zukunft ist es möglich, dass die GIL könnte kaputtgehen nach unten in feinkörnigen Schleusen, so dass damit mehr und mehr Code auszuführen tatsächlich parallel, aber das ist so weit weg, es ist nicht einmal geplant noch.

  3. JRuby implementiert Ruby-Threads als native Threads , wo „native Threads“ im Fall der JVM bedeutet offensichtlich „JVM Threads“. JRuby erlegt keine zusätzliche Verriegelung auf sich. Also, ob diese Fäden in tatsächlich parallel ausgeführt werden können, hängt von die JVM: einige JVMs JVM Themen wie OS Threads implementieren und einige als Green Threads. (Der Mainstream-JVMs von Sun / Oracle-Threads ausschließlich OS verwenden, da JDK 1.3)

  4. XRuby auch implementiert Ruby-Threads als JVM Threads . Aktualisieren :. XRuby ist tot

  5. IronRuby implementiert Ruby-Threads als native Threads , wo „native Threads“ im Fall der CLR offensichtlich bedeutet, "CLR Threads". IronRuby erlegt keine zusätzliche Verriegelung auf sie, so sollten sie parallel laufen, solange Ihre CLR unterstützt das.

  6. Ruby.NET auch implementiert Ruby-Threads als CLR Themen . Update:. Ruby.NET ist tot

  7. Rubinius implementiert Ruby-Themen wie Grüne Themen innerhalb seiner Virtual Machine . Genauer gesagt: die Rubinius VM exportiert eine sehr leicht, sehr flexibel concurrency / Parallelismus / nicht-lokaler Steuerfluss Konstrukt, genannt eine „ Aufgabe “ und alle andere Concurrency-Konstrukte ( Themen im diese Diskussion, aber auch Fortsetzungen , Akteure und andere Sachen) in reinem Rubin umgesetzt, Aufgaben verwendet wird.

    Rubinius kann (derzeit) nicht Zeitplan Threads parallel, aber fügt hinzu, dass nicht zu viel von einem Problem: Rubinius kann bereits mehrere VM-Instanzen in mehreren POSIX Threads laufen in parallel innerhalb eines Rubinius Prozesses. Da Threads sind tatsächlich in Ruby implementiert ist, kann sie wie jede andere Rubin Gegenstand, serialisiert und in einem anderen zu einer anderen VM gesandt werden, POSIX Thread. (Das ist das gleiche Modell der BEAM Erlang VM verwendet für SMP Concurrency. Es ist bereits implementiert für Rubinius Schauspieler .)

    Aktualisieren : Die Informationen über Rubinius in dieser Antwort ist über die Shotgun VM, die nicht mehr existiert. Die „neue“ C ++ VM nicht grünen Fäden über mehrere VMs (dh Erlang / BEAM-Stil) geplant nicht verwendet, verwendet es eine traditionellere einzelne VM mit mehreren nativen OS Threads Modell, genau wie die, eingesetzt von, sagen wir, der CLR, Mono und so ziemlich jede JVM.

  8. MacRuby als Hafen von YARV der oben begann Objective-C Runtime und Corefoundation und Cocoa-Frameworks. Es hat sich nun deutlich von YARV abwich, aber AFAIK es derzeit noch teilt das gleiche Threading-Modell mit YARV . Update:. MacRuby auf Äpfel Garbage Collector abhängt, die als veraltet deklariert und wird in späteren Versionen von Mac OS X entfernt werden, MacRuby ist Untoten

  9. Cardinal für die Parrot Virtual Machine . Es implementiert keine Fäden noch jedoch wenn es das tut, wird es wahrscheinlich implementieren sie als Parrot Themen . Aktualisieren :. Kardinal scheint sehr inaktiv / tot

  10. MagLev ist eine Ruby-Implementierung für die GemStone / S Smalltalk VM . Ich habe keine Informationen, was Threading-Modell GemStone / S verwendet, welche Threading-Modell MagLev verwendet oder auch wenn Themen sind auch noch (wahrscheinlich nicht).

  11. implementiert
  12. HotRuby ist nicht eine vollständige Ruby-Implementierung ihrer besitzen. Es ist eine Implementierung eines YARV Bytecode-VM in JavaScript. HotRuby nicht Threads unterstützen (noch?) Und wenn es ist, werden sie nicht parallel in der Lage zu laufen, weilJavaScript hat keine Unterstützung für echte Parallelität. Es ist ein Actionscript Version von HotRuby, aber, und Actionscript könnte tatsächlich Unterstützung Parallelität. Aktualisieren :. HotRuby ist tot

Leider nur zwei dieser 11 Ruby-Implementierungen sind tatsächlich serienreifen. MRT und JRuby

Wenn Sie also echte parallele Threads wollen, JRuby ist derzeit Ihre nur die Wahl - nicht, dass das ist ein schlechter: JRuby ist eigentlich schneller als MRI und wohl stabiler.

Ansonsten ist die „klassische“ Ruby-Lösung ist es, Prozesse zu verwenden, anstelle von Threads für Parallelität. Die Ruby-Core Library enthält die Process Modul mit der Process.fork Verfahren die es tot einfach macht eine andere Ruby abzweigen Prozess. Außerdem enthält der Ruby-Standard Library die Verteiltes Rubin (dRuby / DRB) Bibliothek, die ermöglicht Rubin Code triviale Weise über mehrere Prozesse verteilt wird, nicht nur auf der gleichen Maschine, sondern auch über das Netzwerk.

Andere Tipps

Ruby 1.8 hat nur grüne Fäden, gibt es keine Möglichkeit, einen echten „OS-Ebene“ Thread zu erstellen. Aber Ruby 1.9 wird eine neue Funktion Fasern genannt, die Sie tatsächlich OS-Level-Threads erstellen können. Leider Ruby 1.9 noch in der Betaphase ist, ist es geplant, in ein paar Monaten stabil.

Eine weitere Alternative ist JRuby zu verwenden. JRuby implementiert Threads als OS-Ebene theads, es gibt keine "grünen Fäden" in ihm. Die neueste Version von JRuby ist 1.1.4 und ist äquivalent zu Ruby 1.8

Es hängt von der Umsetzung:

  • MRT nicht hat, ist YARV näher.
  • JRuby und MacRuby haben.



Ruby hat Verschlüsse als Blocks, lambdas und Procs. Um den vollen Nutzen von Verschlüssen und mehrere Kerne in JRuby, Java Exekutoren kommen in praktisch; für MacRuby mag ich GCD die Warteschlangen .
Beachten Sie, dass, in der Lage zu sein schaffen real „OS-level“ Themen bedeutet nicht, dass Sie mehr CPU-Kern für die parallele Verarbeitung verwenden können. Schauen Sie sich die Beispiele unten.

Dies ist die Ausgabe von einem einfachen Ruby-Programm, das mit Ruby 2.1 3 Threads verwendet. 0:

(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 

Wie Sie hier sehen können, gibt es vier OS-Threads, aber nur die mit staatlichen R läuft. Dies ist aufgrund einer Begrenzung in wie Rubys Threads implementiert.



Das gleiche Programm, jetzt mit JRuby. Sie können drei Threads mit Zustand R sehen, was bedeutet, dass sie parallel ausgeführt werden.

(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 


Das gleiche Programm, jetzt mit MacRuby. Darüber hinaus gibt es drei Threads parallel ausgeführt werden. Dies liegt daran, MacRuby Themen sind POSIX-Threads ( real "OS-level" Themen ), und es gibt keine 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 


Noch einmal das gleiche Programm, aber jetzt mit dem guten alten MRI. Aufgrund der Tatsache, dass diese Implementierung grün-Threads verwendet, nur ein Thread zeigt nach oben

(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


Wenn Sie Interesse an Ruby-Multi-Threading sind könnten Sie meinen Bericht finden Debuggen parallele Programme mit Gabellader interessant.
Für eine allgemeine Übersicht über die Ruby-Interna Rubin unter einem Mikroskop ist ein gutes Buch.
Auch Ruby-Threads und der Global Interpreter sperren in C in Omniref erklären im Quellcode, warum Ruby-Threads nicht parallel ausgeführt werden.

Wie wäre es mit DRB ? Es ist nicht wirklich Multi-Threading, aber die Kommunikation zwischen mehreren Prozessen, aber Sie können es jetzt in 1.8 verwenden und es ist ziemlich geringe Reibung.

Ich werde die „System Monitor“ Antwort auf diese Frage lassen. Ich bin den gleichen Code ausführen (unten, die Primzahlen berechnet) in beiden Fällen Threads laufen auf einer i7 (4 Hyperthreaded-Kern) Maschine mit 8 Rubin ... Der erste Lauf ist mit:

jruby 1.5.6 (Rubin 1.8.7 Patchlevel 249) (2014.02.03 6586) (OpenJDK 64-Bit Server VM 1.7.0_75) [amd64-java]

Die zweite ist mit:

Rubin 2.1.2p95 (2014.05.08) [x86_64-linux-gnu]

Interessanterweise ist die CPU für JRuby Threads höher, aber die Zeit bis zur Fertigstellung ist etwas kürzer für den interpretiert Rubin. Es ist eine Art schwer aus dem Diagramm zu sagen, aber der zweite (interpretiert Rubin) Lauf verwendet etwa 1/2 den CPUs (kein Hyperthreading?)

eingeben Bild Beschreibung hier

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

Wenn Sie MRI verwenden, dann können Sie den Gewinde Code in C schreiben, entweder als Erweiterung oder mit der Rubin-Inline gem.

Wenn Sie wirklich Parallelität benötigen in Ruby für ein Produktionsniveau Systemprozess ist wahrscheinlich eine bessere Alternative (wo man nicht eine Beta verwenden kann).
Aber es ist auf jeden Fall wert Fäden unter JRuby versucht zuerst.

Auch wenn Sie in Zukunft Einfädeln unter Rubin interessiert sind, können Sie diese Artikel nützlich.

Hier einige Informationen über Rinda die Implementierung von Linda Ruby ist (Parallelverarbeitung und verteilte Rechen Paradigma) http://charmalloc.blogspot.com/2009/12/linda-tuples-rinda-drb-parallel.html

Da könnte diese Antwort nicht bearbeiten, so fügen Sie eine neue Antwort hier.

Update (2017.05.08)

Dieser Artikel ist sehr alt, und Informationen werden nicht aktuell folgen (2017) Lauffläche, Im Folgenden einiger Zuschlag:

  1. Opal ein Ruby JavaScript ist Quelle-Source-Compiler. Es hat auch eine Implementierung der Ruby corelib, es derzeit sehr aktiv develompent, und gibt es eine große (Frontend) Rahmen daran gearbeitet. und Produktion bereit. Weil Basis auf Javascript, ist es nicht parallele Threads unterstützen.

  2. truffleruby ist eine Hochleistungs-Implementierung der Programmiersprache Ruby. Aufbauend auf der GraalVM von Oracle Labs, ist TruffleRuby eine Gabel von JRuby, es mit dem Code aus dem Rubinius Projekt kombiniert, und auch von der Standard-Implementierung von Ruby, MRI enthält Code, noch Entwicklung lebt, nicht Produktion bereit. Diese Version Rubin scheinen wie für die Leistung geboren, ich weiß nicht, Unterstützung parallele Threads, wenn, aber ich denke, es sollte.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top