2008-11-20 6 views
30

Ich möchte einen Codeblock in meinem Hauptprozess in den untergeordneten Prozess verschieben, damit er gleichzeitig ausgeführt wird. Ich möchte auch die PID des erzeugten Child-Prozesses haben, damit ich sie überwachen und bei Bedarf töten kann.Wie spawnt du einen Child-Prozess in Ruby?

Antwort

24

Sie können die Kernel-Methode fork verwenden. Hier ein Beispiel:

#!/usr/bin/env ruby 
puts "This is the master process." 

child_pid = fork do 
    puts "This is the child process" 
    exit 
end 

puts "The PID of the child process is #{child_pid}" 

fork Die Methode, um die PID des Prozesses kehrt er sich gabelt und führt jeden Code in dem Block übergeben. Wie normale Ruby-Blöcke behält es die Bindungen des übergeordneten Prozesses bei.

Es ist eine gute Idee, Ihren gegabelten Prozess 10 zu machen.

+1

Eine Sache mit Ruby zu erinnern ist, dass nicht alle Dinge genau so in Windows vs. * nix funktionieren. Manchmal sind sie unter Windows nicht implementiert, also verwenden Sie auf eigene Gefahr. – Daemin

+7

Dieser würde in Windows überhaupt nicht funktionieren – vava

+6

@Vadim Ich denke, das ist eine Funktion, kein Fehler. –

36

Zusätzlich zu Chris 'großer Antwort, denken Sie daran, Process.wait von Ihrem Master zu rufen, um Ihren Kindprozess zu ernten, sonst lassen Sie Zombies zurück.

Beispiel wie in den Kommentaren angefordert:

pid = Process.fork do 
    puts "child, pid #{Process.pid} sleeping..." 
    sleep 5 
    puts "child exiting" 
end 

puts "parent, pid #{Process.pid}, waiting on child pid #{pid}" 
Process.wait 
puts "parent exiting" 
+0

Süße, das war ein toller Tipp. –

+1

Wo und wie würden Sie Process.wait in die obige Antwort einfügen? – iamtoc

+7

Beachten Sie, dass "Process.wait" ohne ein Argument auf _any_ child wartet. In einem allgemeineren Fall würde dieses Code-Snippet den übergeordneten Code daher auch dann beenden, wenn dieser bestimmte untergeordnete Prozess nicht beendet wird. Eine genauere Version würde stattdessen 'Process.wait (pid)' sagen. – sameers

2

Wenn Sie glücklich sind Threads zu verwenden, anstatt Prozesse, dann so etwas wie diese kann ein bisschen mehr skalierbar sein, mehr-als-eine Gabel:

def doit(x) 
    sleep(rand(10)) 
    puts "Done... #{x}" 
end 

thingstodo = ["a","b","c","d","e","f","g"] 
tasklist = [] 

# Set the threads going 

thingstodo.each { |thing| 
    task = Thread.new(thing) { |this| doit(this) } 
    tasklist << task 
} 

# Wait for the threads to finish 

tasklist.each { |task| 
    task.join 
} 

Bitte beachten Sie die exzellenten Kommentare und Referenzen von John Topley zum Ruby-Ausführungsmodell und seinen Einschränkungen.


bearbeitet gerade einen eklatanten Fehler (keine Zuordnung zu Aufgabe) zu korrigieren, und zu folgen @ (Jason King) 's Beratung.

+0

Vermutlich sind dies grüne Threads und keine richtigen OS-Threads? –

+2

Lies das in Bezug auf Ruby 1.9: http://www.igvita.com/2008/11/13/concurrency-is-a-myth-in-ruby/ –

+0

Sollte sein: 'Thread.new (thing) {| it | doit (it)} ' Da' Ding' bei jeder Iteration zurückgesetzt wird, gibt es keine Garantie, dass der richtige Thread das richtige 'Ding' bekommt – smathy

2

Eine gute Alternative zu fork/exec/Laich ist die Posix-Spawn-Juwel für Ruby 1.9: https://github.com/rtomayko/posix-spawn

Sie haben die meisten der harten Arbeit, die es einfacher, effizienter zu gestalten und flexibel im Vergleich zu die untergeordneten Methoden.

Verwandte Themen