Node dirancang untuk menangani operasi I/O secara efisien, tetapi Anda harus tahu bahwa beberapa jenis program tidak cocok untuk mode ini. Misalnya, jika Anda berencana menggunakan Node untuk menangani tugas intensif CPU, Anda dapat memblokir loop acara dan dengan demikian mengurangi respons program. Alternatifnya adalah menetapkan tugas intensif CPU ke proses terpisah untuk ditangani, sehingga membebaskan loop acara. Node memungkinkan Anda untuk menelurkan proses dan menggunakan proses baru ini sebagai anak dari proses induknya. Dalam Node, proses anak dapat berkomunikasi dalam dua arah dengan proses induk, dan sampai batas tertentu, proses induk juga dapat memantau dan mengelola proses anak.
Kasus lain di mana Anda perlu menggunakan proses anak adalah ketika Anda hanya ingin menjalankan perintah eksternal dan membiarkan node mendapatkan nilai pengembalian perintah. Misalnya, Anda dapat menjalankan perintah unix, skrip, atau perintah lain yang tidak dapat dieksekusi secara langsung di Node.
Bab ini akan menunjukkan kepada Anda cara menjalankan perintah eksternal, membuat, dan berkomunikasi dengan anak -anak, dan menghentikan anak -anak. Intinya adalah memberi Anda gambaran tentang cara menyelesaikan serangkaian tugas di luar proses node. Jalankan perintah eksternal Ketika Anda perlu menjalankan perintah shell eksternal atau dapat dieksekusi, Anda dapat menggunakan modul Child_Process untuk mengimpornya seperti ini: Salinan kode adalah sebagai berikut: var child_process = membutuhkan ('child_process') Kemudian Anda dapat menggunakan fungsi EXEC di modul untuk menjalankan perintah eksternal: Salinan kode adalah sebagai berikut: var exec = child_process.exec; exec (perintah, callback); Parameter pertama dari EXEC adalah string perintah shell yang Anda persiapkan untuk dieksekusi, dan parameter kedua adalah fungsi panggilan balik. Fungsi panggilan balik ini akan dipanggil ketika EXEC telah selesai mengeksekusi perintah eksternal atau kesalahan terjadi. Fungsi callback memiliki tiga parameter: kesalahan, stdout, stderr, lihat contoh berikut: Salinan kode adalah sebagai berikut: exec ('ls', function (err, stdout, stderr) { // Catatan Penerjemah: Jika Anda menggunakan Windows, Anda dapat mengubahnya ke perintah Windows, seperti DIR, dan saya tidak akan mengulanginya nanti. }); Jika terjadi kesalahan, parameter pertama akan menjadi instance dari kelas kesalahan. Jika parameter pertama tidak mengandung kesalahan, parameter kedua STDout akan berisi output standar dari perintah. Parameter terakhir berisi output kesalahan terkait perintah. Listing 8-1 menunjukkan contoh yang lebih kompleks dalam melaksanakan perintah eksternal Listing 8-1: Jalankan perintah eksternal (Kode Sumber: Bab8/01_External_Command.js) Salinan kode adalah sebagai berikut: // Impor fungsi EXEC dari Modul Child_Process var exec = membutuhkan ('child_process'). exec; // Memanggil perintah "kucing *.js | wc -l" exec ('cat *.js | wc l', function (err, stdout, stderr) {// baris 4 // Perintah keluar atau panggilan gagal if (err) { // Gagal memulai proses eksternal Console.log ('Child_Process Exit, kode kesalahannya adalah:', err.code); kembali; } } Di baris keempat, kami melewati "Cat *.js | wc -l" sebagai parameter pertama untuk mengeksekusi. Anda juga dapat mencoba perintah lain, selama perintah yang Anda gunakan di shell tidak apa -apa. Kemudian ambil fungsi panggilan balik sebagai parameter kedua, yang akan dipanggil ketika kesalahan terjadi atau proses anak berakhir. Anda juga dapat melewati parameter opsional ketiga sebelum fungsi callback, yang berisi beberapa opsi konfigurasi, seperti: Salinan kode adalah sebagai berikut: var exec = membutuhkan ('child_process'). exec; var options = { Timeout: 1000, KillSignal: 'Sigkill' }; exec ('cat *.js | wc l', opsi, fungsi (err, stdout, stderr) { //… }); Parameter yang dapat digunakan adalah: 1.CWD - Direktori saat ini, Anda dapat menentukan direktori kerja saat ini. 2. Pengkodean-Format pengkodean dari konten output proses anak, nilai default adalah "UTF8", yaitu, pengkodean UTF-8. Jika output dari proses anak bukan UTF8, Anda dapat menggunakan parameter ini untuk mengaturnya. Format penyandian yang didukung adalah: Salinan kode adalah sebagai berikut: ASCII UTF8 UCS2 base64 Jika Anda ingin tahu lebih banyak tentang format pengkodean ini yang didukung oleh Node, silakan merujuk ke Bab 4 "menggunakan buffer untuk memproses, pengkodean, dan decoding data biner". 1. Timeout - Batas waktu eksekusi perintah dalam milidetik, standarnya adalah 0, yaitu, tidak ada batasan, dan tunggu sampai proses anak berakhir. 2.MaxBuffer - Menentukan jumlah maksimum byte yang diizinkan oleh aliran stdout dan aliran stderr. Jika nilai maksimum tercapai, proses anak akan dibunuh. Nilai default adalah 200*1024. 3. KillSignal - Sinyal akhir yang dikirim ke proses anak ketika batas waktu atau cache output mencapai nilai maksimum. Nilai default adalah "SIGTERM", yang akan mengirim sinyal terminasi ke proses anak. Ini biasanya digunakan untuk mengakhiri proses dengan cara yang tertib. Saat menggunakan sinyal SIGTER, proses juga dapat memproses atau menulis ulang perilaku default dari prosesor sinyal setelah menerimanya. Jika proses target membutuhkannya, Anda dapat memberikan sinyal lain untuk itu pada saat yang sama (seperti SIGUSR1). Anda juga dapat memilih untuk mengirim sinyal SigKill, yang akan diproses oleh sistem operasi dan memaksa proses anak untuk segera diakhiri, sehingga setiap operasi pembersihan dari proses anak tidak akan dilakukan. Jika Anda ingin lebih mengontrol akhir proses, Anda dapat menggunakan perintah Child_Process.Spawn, yang akan diperkenalkan nanti. 1.EVN - Menentukan variabel lingkungan yang diteruskan ke proses anak. Standarnya adalah nol, yang berarti bahwa proses anak akan mewarisi variabel lingkungan dari semua proses induk sebelum dibuat. Catatan: Menggunakan opsi KillSignal, Anda dapat mengirim sinyal ke proses target sebagai string. Dalam simpul, sinyal ada sebagai string. Berikut adalah daftar sinyal UNIX dan operasi default yang sesuai: Anda mungkin ingin memberikan satu set variabel lingkungan induk yang dapat diperluas untuk proses anak. Jika Anda secara langsung memodifikasi objek proses.env, Anda akan mengubah variabel lingkungan dari semua modul dalam proses node, yang akan menyebabkan banyak masalah. Alternatifnya adalah membuat objek baru dan menyalin semua parameter di Process.env, lihat Contoh 8-2: Listing 8-2: Gunakan variabel lingkungan parameterisasi untuk menjalankan perintah (Kode Sumber: Bab8/02_ENV_VARS_AUGMENT.js) Salinan kode adalah sebagai berikut: var env = process.env, nama varn, envcopy = {}, exec = membutuhkan ('child_process'). exec; // salin proses.env ke envcopy untuk (vaname in ev) { envcopy [varname] = env [varname]; } // atur beberapa variabel khusus envcopy ['custom env var1'] = 'beberapa nilai'; envcopy ['custom env var2'] = 'beberapa nilai lain'; // Jalankan perintah menggunakan proses.env dan variabel khusus exec ('ls la', {env: envcopy}, function (err, stdout, stderr) { if (err) {throw err; } console.log ('stdout:', stdout); console.log ('stderr:', stderr); } Dalam contoh di atas, variabel envcopy dibuat untuk menyimpan variabel lingkungan. Ini pertama -tama menyalin variabel lingkungan dari proses simpul dari proses.env, kemudian menambahkan atau menggantikan beberapa variabel lingkungan yang perlu dimodifikasi, dan akhirnya melewati envcopy sebagai parameter variabel lingkungan ke fungsi EXEC dan menjalankan perintah eksternal. Ingatlah bahwa variabel lingkungan dilewatkan di antara proses melalui sistem operasi, dan semua jenis nilai variabel lingkungan sampai pada proses anak sebagai string. Misalnya, jika proses induk mengambil angka 123 sebagai variabel lingkungan, proses anak akan menerima "123" sebagai string. Dalam contoh berikut, dua skrip node akan dibuat di direktori yang sama: Parent.js dan Child.js. Script pertama akan memanggil yang kedua. Mari kita buat dua file ini: Listing 8-3: Proses induk menetapkan variabel lingkungan (Bab8/03_environment_number_parent.js) Salinan kode adalah sebagai berikut: var exec = membutuhkan ('child_process'). exec; exec ('node child.js', {env: {number: 123}}, function (err, stdout, stderr) { if (err) {throw err; } console.log ('stdout:/n', stdout); console.log ('stderr:/n', stderr); }); Simpan kode ini ke Parent.js. Berikut ini adalah kode sumber dari proses anak dan menyimpannya ke Child.js (lihat Contoh 8-4) Contoh 8-4: Variabel Lingkungan Subprocess Parses (Bab8/04_environment_number_child.js) Salinan kode adalah sebagai berikut: var number = process.env.number; console.log (typeof (angka)); // → "string" angka = parseInt (angka, 10); console.log (typeof (angka)); // → "Nomor" Setelah Anda menyimpan file ini sebagai Child.js, Anda dapat menjalankan perintah berikut di direktori ini: Salinan kode adalah sebagai berikut: $ node Parent.js Anda akan melihat output berikut: Salinan kode adalah sebagai berikut: Sdtou: rangkaian nomor Stderr: Seperti yang Anda lihat, meskipun proses induk melewati variabel lingkungan numerik, proses anak menerimanya sebagai string (lihat baris kedua output), dan di baris ketiga Anda mengurai string ke dalam angka. Menghasilkan proses anak Seperti yang Anda lihat, Anda dapat menggunakan fungsi Child_Process.exec () untuk memulai proses eksternal dan memanggil fungsi panggilan balik Anda di akhir proses. Ini sangat mudah digunakan, tetapi ada beberapa kelemahan: 1. Selain menggunakan parameter baris perintah dan variabel lingkungan, exec () tidak dapat berkomunikasi dengan proses anak. 2. Output dari proses anak di -cache, jadi Anda tidak dapat mengalirkannya, mungkin kehabisan memori Untungnya, modul Child_Process Node memungkinkan granularitas yang lebih baik untuk mengendalikan awal, berhenti, dan operasi konvensional lainnya dari proses anak. Anda dapat memulai proses anak baru dalam aplikasi. Node menyediakan saluran komunikasi dua arah, yang memungkinkan proses orang tua dan anak untuk mengirim dan menerima data string dari satu sama lain. Proses induk juga dapat memiliki beberapa operasi manajemen untuk proses anak, mengirim sinyal ke proses anak, dan secara paksa menutup proses anak. Buat Proses Anak Anda dapat menggunakan fungsi child_process.spawn untuk membuat proses anak baru, lihat Contoh 8-5: Contoh 8-5: Menghasilkan proses anak. (BAB8/05_SPAWNING_CHILD.JS) Salinan kode adalah sebagai berikut: // Impor fungsi spawn dari modul Child_Process var spawn = membutuhkan ('child_process'). spawn; // menghasilkan proses anak yang digunakan untuk menjalankan perintah "tail -f /var/log/system.log" var child = spawn ('tail', ['-f', '/var/log/system.log']); Kode di atas menghasilkan proses anak yang digunakan untuk menjalankan perintah ekor dan mengambil "-f" dan "/bar/log/system.log" sebagai parameter. Perintah ekor akan memantau file /var/log/system.og (jika ada), dan kemudian output semua ditambahkan data baru ke aliran output standar stdout. Fungsi Spawn mengembalikan objek ChildProcess, yang merupakan objek pointer, merangkum antarmuka akses dari proses nyata. Dalam contoh ini, kami menetapkan deskriptor baru ini ke variabel yang disebut anak. Dengarkan data dari proses anak Setiap pegangan proses anak yang berisi atribut STDout akan mengambil output standar dari proses anak sebagai objek aliran. Anda dapat mengikat acara data pada objek aliran ini, sehingga setiap kali blok data tersedia, fungsi panggilan balik yang sesuai akan dipanggil, lihat contoh berikut: Salinan kode adalah sebagai berikut: // Cetak output proses anak ke konsol child.stdout.on ('data', function (data) { console.log ('output ekor:' + data); }); Setiap kali proses anak menghasilkan data ke stdout output standar, proses induk diberitahu dan mencetak data ke konsol. Selain output standar, proses ini memiliki aliran output default lain: aliran kesalahan standar, yang biasanya digunakan untuk mengeluarkan informasi kesalahan. Dalam contoh ini, jika file /var/log/system.log tidak ada, proses ekor akan menghasilkan pesan yang mirip dengan yang berikut: "/var/log/system.log: Tidak ada file atau direktori tersebut". Dengan mendengarkan aliran Stderr, proses induk akan diberitahu ketika kesalahan ini terjadi. Proses induk dapat mendengarkan aliran kesalahan standar seperti ini: Salinan kode adalah sebagai berikut: child.stderr.on ('data', function (data) { console.log ('output kesalahan ekor:', data); }); Properti Stderr, seperti Stdout, juga merupakan aliran baca saja. Setiap kali proses anak menghasilkan data ke dalam aliran kesalahan standar, proses induk akan diberitahu dan data output. Kirim Data ke Proses Anak Selain menerima data dari aliran output dari proses anak, proses induk juga dapat menulis data ke dalam input standar proses anak melalui properti childpoces.stdin untuk mengirim data ke proses anak. Proses anak dapat mendengarkan data input standar melalui proses read-only proses. Contoh 8-6 akan membuat program yang berisi fungsi-fungsi berikut: 1.+1 Aplikasi: Aplikasi sederhana yang dapat menerima bilangan bulat dari input standar, kemudian menambahkannya, dan kemudian output hasilnya setelah penambahan ke aliran output standar. Sebagai layanan komputasi sederhana, aplikasi ini mensimulasikan proses node sebagai layanan eksternal yang dapat melakukan tugas -tugas tertentu. 2. Uji klien aplikasi +1, kirim bilangan bulat acak, dan kemudian output hasilnya. Digunakan untuk menunjukkan bagaimana proses node menghasilkan proses anak dan kemudian memungkinkannya melakukan tugas -tugas tertentu. Gunakan kode berikut dalam Contoh 8-6 untuk membuat file bernama Plus_one.js: Contoh 8-6: +1 Aplikasi (Bab8/06_Plus_one.js) Salinan kode adalah sebagai berikut: // Kembalikan aliran input standar yang dijeda secara default Process.stdin.resume (); process.stdin.on ('data', fungsi (data) { Nomor VAR; mencoba { // parsing data input ke dalam bilangan bulat angka = parseInt (data.toString (), 10); // +1 Angka += 1; // hasil output process.stdout.write (angka + "/n"); } catch (err) { process.stderr.write (err.message + "/n"); } }); Dalam kode di atas, kami menunggu data dari aliran input standar STDIN. Setiap kali data tersedia, kami menganggap itu adalah integer dan menguraikannya ke dalam variabel integer, kemudian tambahkan 1, dan output hasilnya ke aliran output standar. Anda dapat menjalankan program ini melalui perintah berikut: Salinan kode adalah sebagai berikut: $ node plus_one.js Setelah berjalan, program mulai menunggu input. Jika Anda memasukkan bilangan bulat dan tekan enter, Anda akan melihat nomor setelah ditambahkan 1 untuk ditampilkan di layar. Anda dapat keluar dari program dengan menekan Ctrl-C. Klien tes Sekarang Anda ingin membuat proses node untuk menggunakan layanan komputasi yang disediakan oleh "aplikasi +1" sebelumnya. Pertama-tama buat file bernama plus_one_test.js, lihat Contoh 8-7: Contoh 8-7: Tes +1 Aplikasi (Bab8/07_Plus_one_test.js) Salinan kode adalah sebagai berikut: var spawn = membutuhkan ('child_process'). spawn; // menghasilkan proses anak untuk menjalankan aplikasi +1 var child = spawn ('node', ['plus_one.js']); // Panggil fungsi setiap detik setInterval (function () { // Buat nomor acak lebih kecil dari 10.000 var number = math.floor (math.random () * 10000); // Kirim nomor itu ke proses anak: child.stdin.write (angka + "/n"); // Dapatkan tanggapan dari proses anak dan cetak: child.stdout.once ('data', function (data) { console.log ('anak menjawab' + angka + 'dengan:' + data); }); }, 1000); child.stderr.on ('data', function (data) { Process.stdout.write (data); }); Dari baris pertama ke baris keempat, proses anak mulai menjalankan "aplikasi +1", dan kemudian operasi berikut dilakukan setiap detik menggunakan fungsi setInterval: 1. Buat nomor acak baru kurang dari 10000 2. Lewati nomor ini sebagai string ke proses anak 3. Tunggu proses proses anak untuk membalas string 4. Karena Anda hanya ingin menerima 1 nomor sekaligus, Anda perlu menggunakan Child.stdout.Nce, bukan Child.stdout.on. Jika yang terakhir digunakan, fungsi panggilan balik dari acara data akan didaftarkan setiap 1 detik. Setiap fungsi panggilan balik yang terdaftar akan dieksekusi ketika stdout dari proses anak menerima data. Dengan cara ini, Anda akan menemukan bahwa hasil perhitungan yang sama akan menjadi output beberapa kali. Perilaku ini jelas salah. Menerima pemberitahuan saat proses anak keluar Ketika proses anak keluar, acara keluar akan dipecat. Contoh 8-8 menunjukkan cara mendengarkannya: Contoh 8-8: Dengarkan acara keluar dari proses anak (Bab8/09_Listen_Child_Exit.js) Salinan kode adalah sebagai berikut: var spawn = membutuhkan ('child_process'). spawn; // menghasilkan proses anak untuk menjalankan perintah "ls -la" var child = spawn ('ls', ['-la']); child.stdout.on ('data', function (data) { console.log ('data dari anak:' + data); }); // Saat proses anak keluar: <strong> child.on ('Exit', function (code) { console.log ('Proses anak diakhiri dengan kode' + kode); }); </strong> Dalam beberapa baris Kode Hitam terakhir, proses induk menggunakan acara Exit Process Child untuk mendengarkan acara keluarnya. Ketika peristiwa terjadi, konsol menampilkan output yang sesuai. Kode keluar dari proses anak akan diteruskan ke fungsi panggilan balik sebagai parameter pertama. Beberapa program menggunakan kode keluar non-0 untuk mewakili keadaan kegagalan tertentu. Misalnya, jika Anda mencoba menjalankan perintah "ls al click filename.txt", tetapi direktori saat ini tidak memiliki file ini, Anda akan mendapatkan kode keluar dengan nilai 1, lihat Contoh 8-9: Contoh 8-9: Dapatkan kode keluar dari proses anak (bab8/10_child_exit_code.js) Salinan kode adalah sebagai berikut: var spawn = membutuhkan ('child_process'). spawn; // menghasilkan proses anak dan menjalankan perintah "ls do_not_exist.txt" var child = spawn ('ls', ['doN_not_exist.txt']); // Saat proses anak keluar Child.on ('Exit', function (code) { console.log ('Proses anak diakhiri dengan kode' + kode); }); Dalam contoh ini, acara keluar memicu fungsi panggilan balik dan melewati kode keluar proses anak sebagai parameter pertama untuk itu. Jika proses anak keluar secara tidak normal karena dibunuh oleh sinyal, kode sinyal yang sesuai akan diteruskan ke fungsi panggilan balik sebagai parameter kedua, seperti pada Contoh 8-10: Listing 8-10: Dapatkan sinyal keluar dari proses anak (Bab8/11_Child_exit_signal.js) Salinan kode adalah sebagai berikut: var spawn = membutuhkan ('child_process'). spawn; // menghasilkan proses anak dan menjalankan perintah "tidur 10" var child = spawn ('sleep', ['10']); setTimeout (function () { child.kill (); }, 1000); Child.on ('Exit', Function (kode, sinyal) { if (kode) { console.log ('Proses anak diakhiri dengan kode' + kode); } lain jika (sinyal) { console.log ('proses anak diakhiri karena sinyal' + sinyal); } }); Dalam contoh ini, proses anak mulai melakukan tidur 10 detik, tetapi sinyal Sigkill dikirim ke proses anak sebelum 10 detik, yang akan menghasilkan output berikut: Salinan kode adalah sebagai berikut: proses anak diakhiri karena sinyal sigterm Kirim sinyal dan bunuh prosesnya Di bagian ini, Anda akan belajar cara menggunakan sinyal untuk mengelola subproses. Sinyal adalah cara mudah bagi proses orang tua untuk berkomunikasi dengan anak -anak dan bahkan membunuh anak -anak. Kode sinyal yang berbeda mewakili makna yang berbeda, dan ada banyak sinyal, beberapa di antaranya adalah yang paling umum digunakan untuk membunuh proses. Jika suatu proses menerima sinyal bahwa ia tidak tahu cara menangani, program akan terganggu oleh pengecualian. Beberapa sinyal diproses oleh subproses, sementara yang lain hanya dapat diproses oleh sistem operasi. Secara umum, Anda dapat menggunakan metode anak. Salinan kode adalah sebagai berikut: var spawn = membutuhkan ('child_process'). spawn; var child = spawn ('sleep', ['10']); setTimeout (function () { child.kill (); }, 1000); Anda juga dapat mengirim sinyal spesifik dengan meneruskan string yang mengidentifikasi sinyal sebagai satu -satunya parameter dari metode pembunuhan: Salinan kode adalah sebagai berikut: child.kill ('sigusr2'); Perlu dicatat bahwa meskipun nama metode ini dibunuh, sinyal yang dikirim tidak selalu membunuh proses anak. Jika anak memproses sinyal, perilaku sinyal default ditimpa. Subproses yang ditulis dalam Node dapat menulis ulang definisi prosesor sinyal seperti berikut: Salinan kode adalah sebagai berikut: process.on ('sigusr2', function () { Console.log ('Got a Sigusr2 Sinyal'); }); Sekarang, Anda telah mendefinisikan prosesor sinyal SIGUSR2. Ketika proses Anda menerima sinyal SIGUSR2 lagi, itu tidak akan dibunuh, tetapi sebaliknya menghasilkan kalimat "mendapat sinyal SigUsr2". Dengan menggunakan mekanisme ini, Anda dapat merancang cara sederhana untuk berkomunikasi dengan proses anak atau bahkan memerintahkannya. Meskipun tidak kaya menggunakan input standar, metode ini jauh lebih sederhana. ringkasan Dalam bab ini, kami belajar menggunakan metode Child_Process.exec untuk menjalankan perintah eksternal. Dengan cara ini, kita dapat meneruskan parameter ke proses anak alih -alih menggunakan parameter baris perintah, tetapi sebaliknya mendefinisikan variabel lingkungan. Saya juga belajar cara menghasilkan proses anak dengan menelepon metode Child_Process.Spawn untuk memanggil perintah eksternal. Dengan cara ini, Anda dapat menggunakan aliran input dan aliran output untuk berkomunikasi dengan proses anak, atau menggunakan sinyal untuk berkomunikasi dengan proses anak dan membunuh proses.