Zurückgeben von Daten aus gegabelt Prozessen
Frage
Wenn ich das tue
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 ...)
Lösung 3
Ich wickelte alle Lösungen, die ich auf dem Weg zu finden (einige andere Probleme wie Benutzer + Rohr-Puffer verlass) in Rubin 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
Andere Tipps
Wir tatsächlich hatten gerade dieses Problem in behandeln Rails Isolationsprüfung . Ich stellte darüber einig auf meinem Blog .
Im Grunde, was Sie tun möchten, ist offen ein Rohr in den Eltern und Kind, und hat das Kind auf das Rohr schreiben. Hier ist eine einfache Möglichkeit, den Inhalt eines Blockes 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, wenn Sie ein in dem Kind benötigen tun, werden Sie keinen Zugang zu dieser Bibliothek in den Eltern haben, so dass Sie nicht ein Objekt dieser Art mit dieser Methode zurückgeben können. Sie können jedoch jede Art zurück, die in beide verfügbar ist.
Beachten Sie auch, dass viele der Details hier (read.close
, Process.wait2(pid)
) sind meist Housekeeping Details, wenn Sie also viel diese verwenden, sollten Sie wahrscheinlich diese in eine Utility-Bibliothek bewegen, die Sie wiederverwenden können.
Schließlich ist zu beachten, dass dies nicht auf Windows oder JRuby funktionieren wird, da sie nicht Forking unterstützen.
Danke für alle Antworten, habe ich meine Lösung und läuft, müssen noch sehen, wie nicht-Forking Umgebungen zu handhaben, aber jetzt funktioniert es:)
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 können es in Aktion sehen @ parallel_specs Rails Plugin
Ja, können Sie einen Subprozess erstellen einen Block innerhalb auszuführen.
Ich empfehle der aw
gem :
Aw.fork! { 6 * 7 } # => 42
Natürlich ist es verhindert, dass Nebenwirkungen:
arr = ['foo']
Aw.fork! { arr << 'FUU' } # => ["foo", "FUU"]
arr # => ["foo"]
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 nil
erhält).
Die Gabel Kommunikation zwischen zwei Unix-Prozessen ist in erster Linie der Return-Code und nichts mehr. Allerdings Sie eine FileDescriptor zwischen den beiden Prozessen öffnen konnten und die Datenübertragung zwischen den Prozessen über diesen FileDescriptor. Dies ist die normale Unix Rohr Art und Weise
Wenn Sie Marshal.dump () und Marshal.load () Werte übergeben würden, könnte man leicht Ruby-Objekte zwischen diesen Ruby-Prozessen übergeben.
Sie können die Shared-Memory, dies zu tun, wenn das Kind nur ein kleines Stück von 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 kann ziemlich schwierig sein, aber, und auf diese Weise Shared-Memory-Zugriff ist ein großer Teil des Grundes - jedes Mal, wenn Sie eine Variable haben und ein anderen Prozess könnte es unter Ihnen ändern, sollten Sie sehr vorsichtig sein. Alternativ können Sie auch ein Rohr verwendet werden, die mehr umständlich ist aber wahrscheinlich sicherer für alle, aber die meist trivialen Codes, und können auch verwendet werden, jeden 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 :-)