fork(2)
-Aufrufe werden langsamer, da der übergeordnete Prozess aufgrund der Notwendigkeit, Seitentabellen zu kopieren, mehr Speicher benötigt. In vielen gängigen Anwendungen von fork(), bei denen eine Funktion aus der exec-Familie folgt, um untergeordnete Prozesse zu erzeugen ( Kernel#system
, IO::popen
, Process::spawn
usw.), ist es möglich, diesen Overhead zu entfernen durch die Verwendung spezieller Prozess-Spawning-Schnittstellen ( posix_spawn()
, vfork()
usw.)
Die posix-spawn-Bibliothek zielt darauf ab, eine Teilmenge der Ruby 1.9 Process::spawn
-Schnittstelle so zu implementieren, dass schnelle Prozess-Spawning-Schnittstellen genutzt werden, sofern verfügbar, und vernünftige Fallbacks auf Systemen bieten, die dies nicht tun.
Process::spawn
-Schnittstelle von Ruby 1.9 und erweiterte Versionen von Kernel#system
, Kernel#`
usw. unter Ruby >= 1.8.7 (derzeit nur MRI).POSIX::Spawn::Child
-Klasse für schnelle (aber korrekte!) Nicht-Streaming-IPC-Szenarien. Die folgenden Benchmarks veranschaulichen die Zeit posix-spawn-benchmark
die zum Forken/Ausführen eines untergeordneten Prozesses bei zunehmender Größe des residenten Speichers unter Linux 2.6 und MacOS
posix_spawn
ist schneller als fork+exec
und wird bei Verwendung mit POSIX_SPAWN_USEVFORK
in konstanter Zeit ausgeführt.
fork+exec
ist für große übergeordnete Prozesse extrem langsam.
posix_spawn
ist schneller als fork+exec
, wird aber von der Größe des übergeordneten Prozesses nicht beeinflusst.
Diese Bibliothek umfasst zwei unterschiedliche Schnittstellen: POSIX::Spawn::spawn
, eine Prozess-Spawn-Schnittstelle auf niedrigerer Ebene, die auf der neuen Ruby 1.9 Process::spawn
-Methode basiert, und POSIX::Spawn::Child
, eine Klasse auf höherer Ebene, die auf einfaches Spawnen ausgerichtet ist von Prozessen mit einfacher stringbasierter Standard-Eingabe-/Ausgabe-/Fehlerstrombehandlung. Ersteres ist viel vielseitiger, letzteres erfordert für bestimmte gängige Szenarien viel weniger Code.
Das POSIX::Spawn
-Modul (mit Hilfe der begleitenden C-Erweiterung) implementiert eine Teilmenge der Ruby 1.9 Process::spawn-Schnittstelle, größtenteils durch die Verwendung der IEEE Std 1003.1 posix_spawn(2)
-Systemschnittstellen. Diese werden von verschiedenen UNIX-Betriebssystemen weitgehend unterstützt.
In ihrer einfachsten Form kann die Methode POSIX::Spawn::spawn
verwendet werden, um einen untergeordneten Prozess ähnlich wie Kernel#system
auszuführen:
require 'posix/spawn'
pid = POSIX::Spawn::spawn('echo', 'hello world')
stat = Process::waitpid(pid)
Die erste Zeile führt echo
mit einem einzelnen Argument aus und gibt sofort die pid
des neuen Prozesses zurück. Die zweite Zeile wartet auf den Abschluss des Prozesses und gibt ein Process::Status
-Objekt zurück. Beachten Sie, dass spawn
nicht wie system
auf die Beendigung der Ausführung des Prozesses wartet und nicht den Exit-Status des untergeordneten Elements erhält – Sie müssen Process::waitpid
(oder ein Äquivalent) aufrufen, sonst wird der Prozess zu einem Zombie.
Die spawn
-Methode ist in der Lage, eine große Anzahl zusätzlicher Vorgänge auszuführen, von der Einrichtung der neuen Prozessumgebung über die Änderung des Arbeitsverzeichnisses des untergeordneten Prozesses bis hin zur Umleitung beliebiger Dateideskriptoren.
Weitere Informationen finden Sie in der Ruby 1.9 Process::spawn
Dokumentation und im Abschnitt STATUS
weiter unten für eine vollständige Beschreibung der verschiedenen Process::spawn
Funktionen, die von POSIX::Spawn::spawn
unterstützt werden.
system
, popen4
und `
Zusätzlich zur spawn
-Methode werden Ruby 1.9-kompatible Implementierungen von Kernel#system
und Kernel#`
im POSIX::Spawn
Modul bereitgestellt. Die popen4
-Methode kann verwendet werden, um einen Prozess mit umgeleiteten stdin-, stdout- und stderr-Objekten zu erzeugen.
Das POSIX::Spawn
-Modul kann auch in Klassen und Module eingemischt werden, um spawn
und alle Dienstprogrammmethoden in diesem Namespace einzuschließen:
require 'posix/spawn'
class YourGreatClass
include POSIX::Spawn
def speak(message)
pid = spawn('echo', message)
Process::waitpid(pid)
end
def calculate(expression)
pid, in, out, err = popen4('bc')
in.write(expression)
in.close
out.read
ensure
[in, out, err].each { |io| io.close if !io.closed? }
Process::waitpid(pid)
end
end
Die Klasse POSIX::Spawn::Child
enthält Logik zum Ausführen untergeordneter Prozesse und zum Lesen/Schreiben aus ihren Standardeingabe-, Ausgabe- und Fehlerströmen. Es ist so konzipiert, dass es alle Eingaben in einer einzigen Zeichenfolge aufnimmt und alle Ausgaben als einzelne Zeichenfolgen bereitstellt. Daher eignet es sich nicht gut zum Streamen großer Datenmengen in und aus Befehlen. Dennoch hat es einige Vorteile:
select(2)
) – behandelt alle Pipe-Hang-Fälle aufgrund der Überschreitung PIPE_BUF
Grenzwerte für einen oder mehrere Streams. POSIX::Spawn::Child
verwendet bei der Instanziierung die Standard- spawn
-Argumente und führt den Prozess bis zum Abschluss aus, nachdem alle Eingaben geschrieben und alle Ausgaben gelesen wurden:
>> require 'posix/spawn'
>> child = POSIX::Spawn::Child.new('git', '--help')
Rufen Sie die in stdout/stderr geschriebene Prozessausgabe ab oder überprüfen Sie den Exit-Status des Prozesses:
>> child.out
=> "usage: git [--version] [--exec-path[=GIT_EXEC_PATH]]n ..."
>> child.err
=> ""
>> child.status
=> #<Process::Status: pid=80718,exited(0)>
Verwenden Sie die Option :input
um unmittelbar nach dem Spawnen Daten in die stdin des neuen Prozesses zu schreiben:
>> child = POSIX::Spawn::Child.new('bc', :input => '40 + 2')
>> child.out
"42n"
Zusätzliche Optionen können verwendet werden, um die maximale Ausgabegröße ( :max
) und die Ausführungszeit ( :timeout
) anzugeben, bevor der untergeordnete Prozess abgebrochen wird. Weitere Informationen finden Sie in den POSIX::Spawn::Child
-Dokumenten.
POSIX::Spawn::Child.new
erzeugt den Prozess sofort, wenn er instanziiert wird. Wenn es daher durch eine Ausnahme unterbrochen wird (entweder aufgrund des Erreichens der maximalen Ausgabegröße, des Zeitlimits oder eines anderen Faktors), ist es nicht möglich, auf die out
oder err
zuzugreifen, da der Konstruktor nicht abgeschlossen wurde.
Wenn Sie die out
und err
abrufen möchten, die verfügbar waren, als der Prozess unterbrochen wurde, verwenden Sie das alternative Formular POSIX::Spawn::Child.build
um das untergeordnete Element zu erstellen, ohne den Prozess sofort zu starten. Rufen Sie exec!
So führen Sie den Befehl an einer Stelle aus, an der Sie etwaige Ausnahmen abfangen können:
>> child = POSIX::Spawn::Child.build('git', 'log', :max => 100)
>> begin
?> child.exec!
?> rescue POSIX::Spawn::MaximumOutputExceeded
?> # limit was reached
?> end
>> child.out
"commit fa54abe139fd045bf6dc1cc259c0f4c06a9285bbn..."
Bitte beachten Sie, dass beim Auslösen der MaximumOutputExceeded
Ausnahme die tatsächlichen kombinierten out
und err
aufgrund der internen Pufferung möglicherweise etwas länger als der :max
Wert sind.
Die Methode POSIX::Spawn::spawn
ist so konzipiert, dass sie möglichst kompatibel mit Process::spawn
von Ruby 1.9 ist. Im Moment handelt es sich um eine kompatible Teilmenge.
Diese Process::spawn
-Argumente werden derzeit für alle Spawn::spawn
, Spawn::system
, Spawn::popen4
und Spawn::Child.new
unterstützt:
env: hash
name => val : set the environment variable
name => nil : unset the environment variable
command...:
commandline : command line string which is passed to a shell
cmdname, arg1, ... : command name and one or more arguments (no shell)
[cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
options: hash
clearing environment variables:
:unsetenv_others => true : clear environment variables except specified by env
:unsetenv_others => false : don't clear (default)
current directory:
:chdir => str : Not thread-safe when using posix_spawn (see below)
process group:
:pgroup => true or 0 : make a new process group
:pgroup => pgid : join to specified process group
:pgroup => nil : don't change the process group (default)
redirection:
key:
FD : single file descriptor in child process
[FD, FD, ...] : multiple file descriptor in child process
value:
FD : redirect to the file descriptor in parent process
:close : close the file descriptor in child process
string : redirect to file with open(string, "r" or "w")
[string] : redirect to file with open(string, File::RDONLY)
[string, open_mode] : redirect to file with open(string, open_mode, 0644)
[string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
FD is one of follows
:in : the file descriptor 0 which is the standard input
:out : the file descriptor 1 which is the standard output
:err : the file descriptor 2 which is the standard error
integer : the file descriptor of specified the integer
io : the file descriptor specified as io.fileno
Diese Optionen werden derzeit NICHT unterstützt:
options: hash
resource limit: resourcename is core, cpu, data, etc. See Process.setrlimit.
:rlimit_resourcename => limit
:rlimit_resourcename => [cur_limit, max_limit]
umask:
:umask => int
redirection:
value:
[:child, FD] : redirect to the redirected file descriptor
file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
:close_others => false : inherit fds (default for system and exec)
:close_others => true : don't inherit (default for spawn and IO.popen)
Die von Posix::Spawn::Child, Posix::Spawn#spawn, Posix::Spawn#system und Posix::Spawn#popen4 bereitgestellte Option :chdir
ist nicht threadsicher, da Prozesse mit dem Systemaufruf posix_spawn(2) erzeugt wurden erbt das Arbeitsverzeichnis des aufrufenden Prozesses. Das Gem „posix-spawn“ umgeht diese Einschränkung im Systemaufruf, indem es das Arbeitsverzeichnis des aufrufenden Prozesses unmittelbar vor und nach dem Spawnen des untergeordneten Prozesses ändert.
Copyright (c) bei Ryan Tomayko und Aman Gupta.
Weitere Informationen zur Lizenz und Weiterverbreitung finden Sie in der COPYING
Datei.