panggilan fork(2)
melambat karena proses induk menggunakan lebih banyak memori karena kebutuhan untuk menyalin tabel halaman. Dalam banyak penggunaan umum fork(), yang diikuti oleh salah satu fungsi keluarga exec untuk menelurkan proses anak ( Kernel#system
, IO::popen
, Process::spawn
, dll.), overhead ini dapat dihilangkan dengan menggunakan antarmuka pemijahan proses khusus ( posix_spawn()
, vfork()
, dll.)
Pustaka posix-spawn bertujuan untuk mengimplementasikan subset antarmuka Process::spawn
Ruby 1.9 dengan cara yang memanfaatkan antarmuka pemijahan proses yang cepat bila tersedia dan menyediakan fallback yang wajar pada sistem yang tidak memilikinya.
Process::spawn
Ruby 1.9 dan versi Kernel#system
yang disempurnakan, Kernel#`
, dll. di bawah Ruby >= 1.8.7 (saat ini hanya MRI).POSIX::Spawn::Child
class tingkat tinggi untuk skenario IPC non-streaming yang cepat (tapi benar!). Tolok ukur berikut menggambarkan waktu yang dibutuhkan untuk melakukan fork/eksekusi proses anak pada peningkatan ukuran memori tetap di Linux 2.6 dan MacOS X. Pengujian dijalankan menggunakan program posix-spawn-benchmark
yang disertakan dengan paket.
posix_spawn
lebih cepat dari fork+exec
, dan dijalankan dalam waktu yang konstan ketika digunakan dengan POSIX_SPAWN_USEVFORK
.
fork+exec
sangat lambat untuk proses induk yang besar.
posix_spawn
lebih cepat dari fork+exec
, tetapi tidak ada yang terpengaruh oleh ukuran proses induk.
Pustaka ini mencakup dua antarmuka berbeda: POSIX::Spawn::spawn
, antarmuka pemijahan proses tingkat lebih rendah berdasarkan metode Process::spawn
Ruby 1.9 yang baru, dan POSIX::Spawn::Child
, kelas tingkat lebih tinggi yang diarahkan untuk pemijahan yang mudah proses dengan penanganan aliran input/output/kesalahan standar berbasis string sederhana. Yang pertama jauh lebih serbaguna, sedangkan yang terakhir membutuhkan lebih sedikit kode untuk skenario umum tertentu.
Modul POSIX::Spawn
(dengan bantuan dari ekstensi C yang menyertainya) mengimplementasikan subset antarmuka Ruby 1.9 Process::spawn, sebagian besar melalui penggunaan antarmuka sistem IEEE Std 1003.1 posix_spawn(2)
. Ini didukung secara luas oleh berbagai sistem operasi UNIX.
Dalam bentuknya yang paling sederhana, metode POSIX::Spawn::spawn
dapat digunakan untuk menjalankan proses anak yang mirip dengan Kernel#system
:
require 'posix/spawn'
pid = POSIX::Spawn::spawn('echo', 'hello world')
stat = Process::waitpid(pid)
Baris pertama mengeksekusi echo
dengan satu argumen dan segera mengembalikan pid
proses baru. Baris kedua menunggu proses selesai dan mengembalikan objek Process::Status
. Perhatikan bahwa spawn
tidak menunggu proses menyelesaikan eksekusi seperti system
dan tidak mendapatkan status keluar anak -- Anda harus memanggil Process::waitpid
(atau yang setara) atau proses akan menjadi zombie.
Metode spawn
mampu melakukan sejumlah besar operasi tambahan, mulai dari menyiapkan lingkungan proses baru, mengubah direktori kerja anak, hingga mengarahkan deskriptor file arbitrer.
Lihat dokumentasi Ruby 1.9 Process::spawn
untuk detailnya dan bagian STATUS
di bawah untuk penjelasan lengkap tentang berbagai fitur Process::spawn
yang didukung oleh POSIX::Spawn::spawn
.
system
, popen4
, dan `
Selain metode spawn
, implementasi Kernel#system
dan Kernel#`
yang kompatibel dengan Ruby 1.9 disediakan dalam modul POSIX::Spawn
. Metode popen4
dapat digunakan untuk menelurkan proses dengan objek stdin, stdout, dan stderr yang dialihkan.
Modul POSIX::Spawn
juga dapat digabungkan ke dalam kelas dan modul untuk menyertakan spawn
dan semua metode utilitas dalam namespace tersebut:
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
Kelas POSIX::Spawn::Child
menyertakan logika untuk mengeksekusi proses anak dan membaca/menulis dari input, output, dan aliran kesalahan standarnya. Ini dirancang untuk mengambil semua input dalam satu string dan menyediakan semua output sebagai string tunggal dan oleh karena itu tidak cocok untuk mengalirkan data masuk dan keluar dalam jumlah besar dari perintah. Meskipun demikian, ini memiliki beberapa manfaat:
select(2)
) - menangani semua kasus pipa macet karena melebihi batas PIPE_BUF
pada satu atau lebih aliran. POSIX::Spawn::Child
mengambil argumen spawn
standar saat dipakai, dan menjalankan proses hingga selesai setelah menulis semua masukan dan membaca semua keluaran:
>> require 'posix/spawn'
>> child = POSIX::Spawn::Child.new('git', '--help')
Ambil keluaran proses yang ditulis ke stdout / stderr, atau periksa status keluar proses:
>> child.out
=> "usage: git [--version] [--exec-path[=GIT_EXEC_PATH]]n ..."
>> child.err
=> ""
>> child.status
=> #<Process::Status: pid=80718,exited(0)>
Gunakan opsi :input
untuk menulis data pada stdin proses baru segera setelah pemijahan:
>> child = POSIX::Spawn::Child.new('bc', :input => '40 + 2')
>> child.out
"42n"
Opsi tambahan dapat digunakan untuk menentukan ukuran keluaran maksimum ( :max
) dan waktu eksekusi ( :timeout
) sebelum proses anak dibatalkan. Lihat dokumen POSIX::Spawn::Child
untuk info lebih lanjut.
POSIX::Spawn::Child.new
memunculkan proses segera ketika dipakai. Akibatnya, jika terganggu oleh pengecualian (baik dari pencapaian ukuran output maksimum, batas waktu, atau faktor lainnya), hasil out
atau err
tidak dapat diakses karena konstruktor tidak menyelesaikannya.
Jika Anda ingin mendapatkan data out
dan err
tersedia saat proses terhenti, gunakan formulir alternatif POSIX::Spawn::Child.build
untuk membuat anak tanpa segera memunculkan proses. Hubungi exec!
untuk menjalankan perintah di tempat di mana Anda dapat menangkap pengecualian apa pun:
>> child = POSIX::Spawn::Child.build('git', 'log', :max => 100)
>> begin
?> child.exec!
?> rescue POSIX::Spawn::MaximumOutputExceeded
?> # limit was reached
?> end
>> child.out
"commit fa54abe139fd045bf6dc1cc259c0f4c06a9285bbn..."
Harap dicatat bahwa ketika pengecualian MaximumOutputExceeded
dimunculkan, gabungan data out
dan err
yang sebenarnya mungkin sedikit lebih panjang dari nilai :max
karena buffering internal.
Metode POSIX::Spawn::spawn
dirancang agar kompatibel dengan Process::spawn
Ruby 1.9. Saat ini, ini adalah subset yang kompatibel.
Argumen Process::spawn
ini saat ini didukung untuk Spawn::spawn
, Spawn::system
, Spawn::popen4
, dan Spawn::Child.new
:
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
Opsi berikut ini TIDAK didukung saat ini:
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)
Opsi :chdir
yang disediakan oleh Posix::Spawn::Child, Posix::Spawn#spawn, Posix::Spawn#system dan Posix::Spawn#popen4 tidak aman untuk thread karena proses muncul dengan panggilan sistem posix_spawn(2) mewarisi direktori kerja dari proses pemanggilan. Permata posix-spawn mengatasi batasan ini dalam panggilan sistem dengan mengubah direktori kerja dari proses pemanggilan segera sebelum dan setelah memunculkan proses anak.
Hak Cipta (c) oleh Ryan Tomayko dan Aman Gupta.
Lihat file COPYING
untuk informasi lebih lanjut tentang lisensi dan redistribusi.