Wenn ichZurückgeben von Daten aus gegabelt Prozesse
Process.fork do
x
end
wie kann ich wissen, was zurückgegeben x (z true/fase/string)?
(Schreiben in eine Datei/Datenbank ist keine Option ...)
Wenn ichZurückgeben von Daten aus gegabelt Prozesse
Process.fork do
x
end
wie kann ich wissen, was zurückgegeben x (z true/fase/string)?
(Schreiben in eine Datei/Datenbank ist keine Option ...)
Ich wickelte alle Lösungen, die ich auf dem Weg gefunden (einige andere Probleme wie Benutzer beenden + Piping-Puffer) in ruby parallel gem. Nun ist es so einfach wie:
results = Parallel.map([1,2,3],:in_processes=>4) do |i|
execute_something(i)
end
oder
results = Parallel.map([1,2,3],:in_threads=>4) do |i|
execute_something(i)
end
Nach der Dokumentation:
Wenn ein Block angegeben wird, dass der Block in der subprocess ausgeführt wird, und die Subprozess endet mit einem Status von Null.
Also, wenn Sie es mit einem Block aufrufen, gibt es 0. Ansonsten funktioniert es im Grunde das gleiche wie das fork()
Systemaufruf auf Unix (das Mutter empfängt die PID des neuen Prozesses, das Kind erhält nil
).
Wie kann diese Hilfe in das bekommen, was die 'x' zurückgekehrt? – grosser
Der Kindprozess läuft (natürlich) in einem separaten Prozess. Um also den Wert von "x" zu erhalten, müssen Sie wahrscheinlich über Sockets, Pipes oder etwas Ähnliches kommunizieren. Ich bezweifle, dass Sie Variablen innerhalb des Blocks festlegen können, die außerhalb des Blocks reflektiert werden, da der untergeordnete Prozess über separaten Speicher usw. verfügt. – mipadi
Die Gabel Kommunikation zwischen zwei Unix-Prozesse ist hauptsächlich der Return-Code und nichts mehr. Sie könnten jedoch einen Dateideskriptor zwischen den beiden Prozessen öffnen und Daten zwischen den Prozessen über diesen Dateideskriptor übergeben: Dies ist der normale Unix-Pipe-Weg.
Wenn Sie die Werte Marshal.dump() und Marshal.load() übergeben würden, könnten Sie problemlos Ruby-Objekte zwischen diesen Ruby-Prozessen übergeben.
Sie können Shared Memory dazu verwenden, wenn das Kind nur ein kleiner Ruby-Code sein muss. So etwas wie die folgenden funktionieren:
str = 'from parent'
Thread.new do
str = 'from child'
end
sleep(1)
puts str # outputs "from child"
Concurrency ziemlich schwierig sein kann, aber, und die gemeinsamen Speicher Zugriff auf diese Art und Weise ist ein großer Teil des Grundes - jedes Mal, wenn Sie eine Variable, und ein anderer Prozess haben könnte es ändern aus unter Ihnen, sollten Sie sehr vorsichtig sein. Alternativ können Sie eine Pipe verwenden, die umständlicher ist, aber wahrscheinlich sicherer für alle außer dem einfachsten Code, und kann auch verwendet werden, um einen beliebigen Befehl auszuführen. Hier ist ein Beispiel, gerade aus dem rdoc für IO.popen:
f = IO.popen("uname")
p f.readlines # outputs "Darwin", at least on my box :-)
Wir haben eigentlich nur dieses Problem in Rails isolation testing behandeln musste. Ich habe darüber einige on my blog geschrieben.
Im Grunde möchten Sie eine Pipe im Parent und Child öffnen und das Kind in die Pipe schreiben lassen. Hier ist eine einfache Möglichkeit, den Inhalt eines Blocks in einem untergeordneten Prozess und wieder um das Ergebnis zu laufen:
def do_in_child
read, write = IO.pipe
pid = fork do
read.close
result = yield
Marshal.dump(result, write)
exit!(0) # skips exit handlers.
end
write.close
result = read.read
Process.wait(pid)
raise "child failed" if result.empty?
Marshal.load(result)
end
Dann könnten Sie laufen:
do_in_child do
require "some_polluting_library"
SomePollutingLibrary.some_operation
end
Beachten Sie, dass, wenn Sie ein benötigen im Kind , Sie haben im übergeordneten Objekt keinen Zugriff auf diese Bibliothek, sodass Sie ein Objekt dieses Typs mit dieser Methode nicht zurückgeben können. Sie können jedoch jeden Typ zurückgeben, der in beiden verfügbar ist.
Beachten Sie auch, dass viele der Details hier (read.close
, Process.wait2(pid)
) meist Housekeeping-Details sind, also wenn Sie diese viel verwenden, sollten Sie diese wahrscheinlich in eine Dienstprogrammbibliothek verschieben, die Sie wiederverwenden können.
Beachten Sie, dass dies unter Windows oder JRuby nicht funktioniert, da Forking nicht unterstützt wird.
Danke für alle Antworten, habe ich meine Lösung und läuft, müssen noch sehen, wie nicht-Forking Umgebungen zu handhaben, aber es funktioniert für jetzt :)
read, write = IO.pipe
Process.fork do
write.puts "test"
end
Process.fork do
write.puts 'test 2'
end
Process.wait
Process.wait
write.close
puts read.read
read.close
Sie es in Aktion sehen können @parallel_specs Rails plugin
Haben Sie den Isolationstest-Link gesehen, den ich in meiner Antwort angegeben habe? Es verarbeitet sowohl Forking- als auch Non-Forking-Umgebungen und kann bereits alles tun, was Sie brauchen. –
Ja, lesen Sie auch Ihren Beitrag darüber, krank hinzuzufügen bald! – grosser
Ja, Sie einen Subprozess erstellen einen Block innerhalb auszuführen.
Ich empfehle the aw
gem:
Aw.fork! { 6 * 7 } # => 42
Natürlich ist es verhindert, dass Nebenwirkungen:
arr = ['foo']
Aw.fork! { arr << 'FUU' } # => ["foo", "FUU"]
arr # => ["foo"]
Können Sie hier Objekte oder sogar Klassen als Parameter übergeben? Ich könnte wirklich einen Weg nutzen, um einen Prozess auszuweiten und ihm eine ganze Umgebung zu übergeben. – Automatico