Teman-teman yang familiar dengan js pasti tahu bahwa js 是单线程
. Di Node, model single-thread multi-proses diadopsi. Karena keterbatasan JavaScript dalam satu thread, pada server multi-core, kita sering kali perlu memulai beberapa proses untuk memaksimalkan kinerja server.
Kluster proses Node.js dapat digunakan untuk menjalankan beberapa instance Node.js, yang dapat mendistribusikan beban kerja di antara thread aplikasinya. Jika isolasi proses tidak diperlukan, gunakan worker_threads
sebagai gantinya, yang memungkinkan beberapa thread aplikasi dijalankan dalam satu instance Node.js.
Node memperkenalkan modul cluster setelah versi V0.8,一个主进程(master) 管理多个子进程(worker) 的方式实现集群
.
Modul cluster memudahkan pembuatan proses anak yang berbagi port server.
Lapisan terbawah cluster adalah modul child_process. Selain mengirim pesan biasa, ia juga dapat mengirim objek dasar
TCP
,UDP
, dll. Modulcluster
adalah aplikasi gabungan dari modulchild_process
dan modulnet
. Ketika cluster dimulai, server TCP akan dimulai secara internal dan deskriptor file dari soket server TCP akan dikirim ke proses kerja.
Dalam aplikasi modul cluster
,一个主进程只能管理一组工作进程
. Mode operasinya tidak sefleksibel modul child_process
, tetapi lebih stabil:
const cluster = require('cluster') dan
.isMaster
mengidentifikasi proses utama, Node<16.isPrimary.isPrimary
proses utama, Node>16.isWorker.isWorker
sub-proses .worker.worker
atas pekerjaan saat ini Referensi ke objek proses [dalam proses anak].workers
menyimpan hash dari objek proses pekerja yang aktif, dengan bidang id
sebagai kuncinya. Hal ini memudahkan untuk mengulang semua proses pekerja. Ini hanya tersedia di proses utama. cluster.wokers[id] === worker
[dalam proses utama].settings
bersifat read-only, item konfigurasi cluster. Setelah memanggil metode .setupPrimary() atau .fork(), objek pengaturan ini akan berisi pengaturan, termasuk nilai default. Sebelumnya merupakan benda kosong. Objek ini tidak boleh diubah atau diatur secara manual.cluster.settings
:- `execArgv` <string[]>Daftar parameter string yang diteruskan ke file eksekusi Node.js. **Bawaan:** `proses.execArgv`. - `exec` <string> Jalur file ke file proses pekerja. **Bawaan:** `proses.argv[1]`. - `args` <string[]> Argumen string diteruskan ke proses pekerja. **Bawaan:** `proses.argv.slice(2)`. - `cwd` <string>Direktori kerja saat ini dari proses pekerja. **Default:** `undefinisi` (diwarisi dari proses induk). - `serialisasi` <string>Menentukan jenis serialisasi yang digunakan untuk mengirim pesan antar proses. Nilai yang mungkin adalah `'json'` dan `'advanced'`. **Bawaan:** `salah`. - `silent` <boolean>Apakah akan mengirim output ke input dan output standar dari proses induk. **Bawaan:** `salah`. - `stdio` <Array> mengonfigurasi input dan output standar dari proses yang dihasilkan. Karena modul cluster bergantung pada IPC untuk dijalankan, konfigurasi ini harus berisi entri `'ipc'`. Jika opsi ini tersedia, opsi ini akan menggantikan `silent`. - `uid` <number> menetapkan ID pengguna proses. - `gid` <number> menetapkan ID grup proses. - `inspectPort` <number> |. <Function> Menyetel port inspektur untuk proses pekerja. Ini bisa berupa angka atau fungsi yang tidak menggunakan parameter dan mengembalikan angka. Secara default, setiap proses pekerja memiliki portnya sendiri, dimulai dari `process.debugPort` proses utama dan terus meningkat. - `windowsHide` <boolean> Menyembunyikan jendela konsol proses yang biasanya dibuat pada sistem Windows. **Bawaan:** `salah`.
.fork([env])
memunculkan proses pekerja baru [dalam proses utama].setupPrimary([settings])
Node>16.setupMaster([settings])
digunakan untuk mengubah perilaku 'fork' default, setelah digunakan Pengaturan akan muncul di cluster.settings
. Perubahan pengaturan apa pun hanya akan memengaruhi panggilan berikutnya ke .fork()
, bukan proses pekerja yang sudah berjalan. Nilai default di atas hanya berlaku untuk panggilan pertama. Node kurang dari 16 [Dalam proses utama].disconnect([callback])
Dipanggil ketika semua proses pekerja terputus dan menutup pegangan [Dalam proses utama]Untuk membuat klaster lebih stabil dan kuat, modul cluster
juga mengekspos banyak Peristiwa:
'message'
, dipicu ketika proses master cluster menerima pesan dari proses pekerja mana pun.'exit'
, ketika proses pekerja mati, modul cluster akan memicu acara 'exit'
.cluster.on('exit', (pekerja, kode, sinyal) => { console.log('pekerja %d meninggal (%s). memulai ulang...', pekerja.proses.pid, sinyal ||.kode); cluster.fork(); });
'listening'
, setelah memanggil listen()
dari proses pekerja, ketika acara 'listening'
dipicu di server, cluster
dalam proses utama juga akan memicu acara 'listening'
.cluster.on('mendengarkan', (pekerja, alamat) => { konsol.log( `Seorang pekerja sekarang terhubung ke ${address.address}:${address.port}`); });
'fork'
, ketika proses pekerja baru muncul, modul cluster akan memicu acara 'fork'
.cluster.on('garpu', (pekerja) => { batas waktu[pekerja.id] = setTimeout(errorMsg, 2000); });
'setup'
, dipicu setiap kali .setupPrimary()
dipanggil.disconnect
dipicu setelah saluran IPC dari proses pekerja terputus. Ketika proses pekerja keluar secara normal, dimatikan, atau terputus secara manualcluster.on('disconnect', (worker) => { console.log(`Pekerja #${worker.id} telah terputus`); });
Objek Worker
berisi semua informasi publik dan metode proses pekerja. Dalam proses utama, Anda dapat menggunakan cluster.workers
untuk mendapatkannya. Dalam proses pekerja, Anda bisa menggunakan cluster.worker
untuk mendapatkannya.
.id
. id
proses pekerja baru diberikan id uniknya sendiri. Ketika proses pekerja masih hidup, ini adalah kunci yang mengindeksnya cluster.workers
..process
Semua proses pekerja dibuat menggunakan child_process.fork()
, dan objek yang dikembalikan oleh fungsi ini disimpan sebagai .process
. Dalam proses pekerja, process
global disimpan..send(message[, sendHandle[, options]][, callback])
mengirimkan pesan ke proses pekerja atau proses utama, dan Anda dapat memilih untuk menggunakan pegangan. Dalam proses utama, ini mengirimkan pesan ke proses pekerja tertentu. Ini sama dengan ChildProcess.send()
. Dalam proses pekerja, ini mengirimkan pesan ke proses utama. Itu sama dengan process.send()
..destroy()
.kill([signal])
Fungsi ini akan mematikan proses pekerja. Fungsi kill()
menghentikan proses pekerja tanpa menunggu pemutusan hubungan yang baik, fungsi ini memiliki perilaku yang sama worker.process.kill()
. Untuk kompatibilitas ke belakang, metode ini diberi nama worker.destroy()
..disconnect([callback])
dikirim ke proses pekerja, menyebabkannya memanggil .disconnect()
miliknya sendiri yang akan mematikan semua server, menunggu peristiwa 'close'
di server tersebut, dan kemudian memutuskan sambungan saluran IPC..isConnect()
Fungsi ini mengembalikan true
jika proses pekerja terhubung ke proses utamanya melalui saluran IPC, false
jika sebaliknya. Proses pekerja terhubung ke proses masternya setelah pembuatan..isDead()
Fungsi ini mengembalikan true
jika proses pekerja telah dihentikan (karena keluar atau menerima sinyal). Jika tidak, ia akan mengembalikan false
.Untuk membuat cluster lebih stabil dan kuat, modul cluster
juga memaparkan banyak peristiwa:
'message'
, dalam proses pekerja.cluster.workers[id].on('message', messageHandler);
'exit'
, ketika proses pekerja mana pun mati, objek当前worker工作进程
akan memicu peristiwa 'exit'
.if (cluster.isPrimary) { const pekerja = cluster.fork(); pekerja.on('keluar', (kode, sinyal) => { jika (sinyal) { console.log(`pekerja terbunuh oleh sinyal: ${signal}`); } else if (kode !== 0) { console.log(`pekerja keluar dengan kode kesalahan: ${code}`); } kalau tidak { console.log('pekerja sukses!'); } }); }
'listening'
, panggil listen()
dari proses pekerja untuk mendengarkan proses pekerja saat ini.cluster.fork().on('mendengarkan', (alamat) => { // Proses pekerja sedang mendengarkan });
disconnect
, yang dipicu setelah saluran IPC dari proses pekerja terputus. Ketika proses pekerja keluar secara normal, dimatikan, atau terputus secara manualcluster.fork().on('disconnect', () => { //Terbatas pada pemicuan pada objek pekerja saat ini});
Dalam Node, komunikasi antar-proses (IPC) digunakan untuk mewujudkan komunikasi antar-proses antara proses utama dan sub-proses .send()
(a.send EventEmitter
mengirim pesan ke Send) metode cluster模块
mengirim pesan dan mendengarkan peristiwa message
untuk mengumpulkan informasi. Ini juga merupakan contoh komunikasi antar-proses sederhana di situs resmi
process.on('message')
, process.send()
child.on('message')
, child.send()
# cluster.isMaster # cluster.garpu() # cluster.pekerja # cluster.workers[id].on('message', messageHandler); # cluster.pekerja[id].kirim(); # proses.on('pesan', messageHandler); # proses.kirim(); const cluster = memerlukan('cluster'); const http = memerlukan('http'); # Proses utama if (cluster.isMaster) { // Melacak permintaan http console.log(`${proses.pid} utama sedang berjalan`); misalkan numReqs = 0; // Hitung permintaan fungsi messageHandler(pesan) { if (pesan.cmd && pesan.cmd === 'notifyRequest') { jumlahPermintaan += 1; } } // Mulai pekerja dan dengarkan pesan yang berisi notifyRequest // Mulai multi-proses (jumlah inti cpu) // Memunculkan proses pekerja. const numCPUs = memerlukan('os').cpus().panjang; untuk (biarkan i = 0; i < jumlahCPU; i++) { konsol.log(i) cluster.fork(); } // proses utama pekerja cluster berkomunikasi dengan proses anak untuk (const id di cluster.workers) { // ***Dengarkan kejadian dari proses anak cluster.workers[id].on('message', messageHandler); // ***Kirim cluster.workers[id].send({ ke proses anak ketik: 'masterToWorker', dari: 'tuan', data: { nomor: Matematika.lantai(Matematika.acak() * 50) } }); } cluster.on('exit', (pekerja, kode, sinyal) => { console.log(`pekerja ${worker.process.pid} meninggal`); }); } kalau tidak { # Proses anak // Proses pekerja dapat berbagi koneksi TCP apa pun // Dalam contoh ini, ini adalah server HTTP // Proses pekerja memiliki server http. http.Server((permintaan, res) => { res.writeHead(200); res.end('halo dunian'); //******! ! ! ! Beritahu master tentang permintaan tersebut! ! ! ! ! ! ******* //****** Kirim proses.kirim({ cmd: 'notifyRequest' }); //****** Dengarkan proses.on('pesan', fungsi(pesan) { // xxxxxxx }) }).mendengarkan(8000); console.log(`Pekerja ${proses.pid} dimulai`); }
Komunikasi antar proses NodeJS hanya melibatkan penyampaian pesan, dan tidak benar-benar mentransfer objek.
Sebelum mengirim pesan, metode send()
akan merakit pesan menjadi sebuah pegangan dan pesan ini akan diserialkan oleh JSON.stringify
ditransmisikan melalui saluran IPC. Semuanya berupa string dan dikembalikan ke objek melalui JSON.parse
setelah transmisi.
Ada app.listen(port)
dalam kode. Saat melakukan forking, mengapa banyak proses dapat mendengarkan port yang sama?
Alasannya adalah proses utama mengirimkan pegangan objek layanan milik proses utama ke beberapa subproses melalui metode send(), sehingga untuk setiap subproses, setelah memulihkan pegangan, mereka mendapatkan objek layanan yang sama. Ketika jaringan Ketika permintaan dibuat ke server, layanan proses bersifat preemptive, jadi tidak ada pengecualian yang akan terjadi ketika mendengarkan pada port yang sama.
# master.js const fork = memerlukan('child_process').fork; const cpus = memerlukan('os').cpus(); for (misalkan i=0; i<cpus.length; i++) { const pekerja = fork('worker.js'); console.log('proses pekerja dibuat, pid: %s ppid: %s', pekerja.pid, proses.pid); }
# pekerja.js const http = memerlukan('http'); http.createServer((permintaan, res) => { res.end('Saya pekerja, pid: ' + proses.pid + ', ppid: ' + proses.ppid); }).listen(3000);
Dalam contoh kode di atas, ketika konsol mengeksekusi
node master.js
hanya satu pekerja yang dapat mendengarkan port 3000, dan sisanya akan memunculkanError: listen EADDRINUSE :::3000
.
发送句柄
antar proses setelah versi v0.5.9/** * http://nodejs.cn/api/child_process.html#child_process_subprocess_send_message_sendhandle_options_callback * pesan * kirimHandle */ subprocess.send(message, sendHandle)
Setelah saluran IPC dibuat antara proses induk dan anak, pesan dikirim melalui metode send dari objek subproses.二个参数sendHandle 就是句柄,可以是TCP套接字、TCP服务器、UDP套接字等
, untuk menyelesaikan masalah penggunaan port multi-proses di atas, kami meneruskan soket proses utama ke proses anak.
# master.js const fork = memerlukan('child_process').fork; const cpus = memerlukan('os').cpus(); const server = memerlukan('net').createServer(); server.mendengarkan(3000); process.title = 'master-simpul' for (misalkan i=0; i<cpus.length; i++) { const pekerja = fork('worker.js'); # Berikan pegangan pada pekerja.send('server', server); console.log('proses pekerja dibuat, pid: %s ppid: %s', pekerja.pid, proses.pid); }
// pekerja.js biarkan pekerja; process.title = 'pekerja simpul' proses.on('pesan', fungsi (pesan, sendHandle) { if (pesan === 'server') { pekerja = sendHandle; pekerja.on('koneksi', fungsi (soket) { console.log('Saya pekerja, pid: ' + proses.pid + ', ppid: ' + proses.ppid) }); } });
Verifikasi bahwa konsol mengeksekusi node master.js
Jika Anda memahami cluster
, Anda akan mengetahui bahwa proses anak dibuat melalui cluster.fork()
. Di Linux, sistem secara asli menyediakan metode fork
, jadi mengapa Node memilih untuk mengimplementasikan cluster模块
sendiri daripada langsung menggunakan metode asli sistem? Alasan utamanya adalah dua poin berikut:
Proses fork memonitor port yang sama, yang akan menyebabkan kesalahan penggunaan port.
Tidak ada penyeimbangan beban antara proses fork, yang dapat dengan mudah menyebabkan fenomena kawanan yang menggelegar
dalam cluster模块
, misalnya masalah pertama, kita menentukan apakah proses saat ini adalah master进程
, jika ya, mendengarkan di port. Jika tidak, itu direpresentasikan sebagai worker进程
garpu dan tidak mendengarkan di port.
Menanggapi pertanyaan kedua, cluster模块
memiliki fungsi penyeimbangan beban bawaan. master进程
bertanggung jawab untuk mendengarkan port untuk menerima permintaan, dan kemudian menugaskannya ke worker进程
yang sesuai melalui algoritma penjadwalan (defaultnya adalah Round-Robin, algoritma penjadwalan dapat dimodifikasi melalui variabel lingkungan NODE_CLUSTER_SCHED_POLICY
).
Ketika kode memunculkan pengecualian yang tidak tertangkap, proses akan keluar. Pada saat ini, Node.js menyediakan antarmuka process.on('uncaughtException', handler)
untuk menangkapnya, tetapi ketika sebuah pengecualian terjadi. Ketika proses Pekerja menemukan pengecualian yang tidak tertangkap, maka proses tersebut sudah dalam keadaan tidak pasti. Pada saat ini, kita harus membiarkan proses keluar dengan baik:
+---------+ +---------+ |.Pekerja |.| +---------+ +----+----+ |.tidak tertangkapException | +----------------+ | |.| |.<----------+ | |.| |.putuskan |.cabangkan pekerja baru | +---------> + ----------------------- -> | |.tunggu... | |.keluar | +---------> | | mati |.| | |.|
Ketika suatu proses memiliki pengecualian yang menyebabkan crash atau OOM dan dimatikan oleh sistem, tidak seperti ketika terjadi pengecualian yang tidak tertangkap, kita masih memiliki kesempatan untuk membiarkan proses tersebut terus dijalankan proses saat ini langsung keluar, dan Master segera melakukan fork pada Pekerja Baru.
Modul child_process menyediakan kemampuan untuk menurunkan proses anak, yang secara sederhana merupakan执行cmd命令的能力
. Secara default, stdin、 stdout 和stderr 的管道会在父Node.js 进程和衍生的子进程之间建立
. Jaringan pipa ini mempunyai kapasitas yang terbatas (dan spesifik platform). Jika proses anak melebihi batas ini saat menulis ke stdout dan tidak ada output yang ditangkap, proses anak akan memblokir dan menunggu buffer pipa menerima lebih banyak data. Ini adalah perilaku yang sama seperti pipa di dalam cangkang. Jika output tidak digunakan, gunakan opsi { stdio: 'ignore' }.
const cp = require('child_process');
Proses anak yang dibuat melalui API tidak memiliki koneksi yang diperlukan dengan proses induk.
4 metode asinkron digunakan untuk membuat proses anak: fork, exec, execFile, spawn
Node
fork(modulePath, args)
: Digunakan ketika Anda ingin menjalankan proses Node sebagai proses independen, sehingga pemrosesan perhitungan dan deskriptor file dipisahkan dari proses utama Node (menyalin proses anak)Non-Node
spawn(command, args)
: Memproses beberapa masalah Gunakan execFile(file, args[, callback]) ketika ada banyak sub-proses I/O atau ketika proses memiliki output dalam jumlah besarexecFile(file, args[, callback])
Gunakan ketika Anda hanya perlu menjalankan program eksternal kecepatan eksekusi cepat dan relatif aman untuk memproses input pengguna.exec(command, options)
: Digunakan ketika Anda ingin mengakses langsung perintah shell thread. Pastikan untuk memperhatikantiga metode sinkronisasi yang dimasukkan oleh pengguna: execSync
, execFileSync
, spawnSync
Tiga metode lainnya adalah ekstensi dari spawn()
.
. Ingat, proses anak Node.js yang diturunkan tidak bergantung pada Proses induk, kecuali saluran komunikasi IPC yang dibangun di antara keduanya. Setiap proses memiliki memorinya sendiri dan instance V8-nya sendiri
.
Misalnya, buat dua file, pekerja.js dan master.js, dalam direktori:
# child.js const t = JSON.parse(proses.argv[2]); console.error(`proses anak t=${JSON.stringify(t)}`); process.send({hello:`son pid=${process.pid} tolong beri ayah process pid=${process.ppid} hello`}); proses.pada('pesan', (pesan)=>{ console.error(`pesan proses anak=${JSON.stringify(msg)}`); });
# induk.js const {garpu} = memerlukan('proses_anak'); untuk(misalkan i = 0; i < 3; i++){ const p = fork('./child.js', [JSON.stringify({id:1,name:1})]); p.on('pesan', (pesan) => { console.log(`messsgae dari pesan anak=${JSON.stringify(msg)}`, ); }); p.send({halo:`Salam dari ayah ${process.pid} process id=${i}`}); }
Jalankan parent.js melalui node parent.js
, lalu periksa jumlah proses melalui ps aux | grep worker.js
Kita dapat menemukan bahwa idealnya, jumlah proses sama dengan jumlah inti CPU, dan setiap proses menggunakan satu inti CPU.
Ini adalah mode Master-Pekerja klasik (mode master-slave)
Faktanya, melakukan forking suatu proses itu mahal, dan tujuan menyalin suatu proses adalah untuk memanfaatkan sepenuhnya sumber daya CPU, sehingga NodeJS menggunakan pendekatan berbasis peristiwa pada satu thread untuk memecahkan masalah konkurensi tinggi.
Skenario yang Berlaku <br/>Umumnya digunakan untuk skenario yang memakan waktu, dan diimplementasikan menggunakan node, seperti mengunduh file;
Fork dapat mengimplementasikan pengunduhan multi-utas: membagi file menjadi beberapa blok, lalu setiap proses mengunduh satu bagian, dan terakhir menyatukannya;
const cp = require('child_process'); // Parameter pertama adalah nama atau jalur file eksekusi yang akan dijalankan. inilah gema cp.execFile('echo', ['halo', 'dunia'], (err, stdout, stderr) => { jika (err) { konsol.kesalahan (err }); konsol.log('stdout: ', stdout); konsol.log('stderr: ', stderr); });
Skenario yang berlaku <br/> Lebih cocok untuk tugas dengan overhead rendah dan lebih memperhatikan hasil, seperti ls, dll.;
terutama digunakan untuk menjalankan metode shell, dan spawn masih dipanggil secara internal, tetapi ada batas maksimum cache.
const cp = require('child_process'); cp.exec(`cat ${__dirname}/messy.txt | sortir | uniq`, (err, stdout, stderr) => { konsol.log(stdout); });
Skenario yang berlaku <br/>Lebih cocok untuk tugas dengan overhead rendah dan lebih memperhatikan hasil, seperti ls, dll.;
tugas tunggal
const cp = require('child_process'); const anak = cp.spawn('echo', ['halo', 'dunia']); child.on('kesalahan', konsol.kesalahan); # Outputnya adalah aliran, output ke proses utama stdout, konsol child.stdout.pipe(process.stdout); child.stderr.pipe(process.stderr);
Rangkaian multi-tugas
const cp = require('child_process'); const jalur = memerlukan('jalur'); const cat = cp.spawn('cat', [path.resolve(__dirname, 'messy.txt')]); const sortir = cp.spawn('sort'); const uniq = cp.spawn('uniq'); #Outputnya adalah aliran cat.stdout.pipe(sort.stdin); sort.stdout.pipe(uniq.stdin); uniq.stdout.pipe(proses.stdout);
Skenario yang berlaku
spawn bersifat streaming, sehingga cocok untuk tugas-tugas yang memakan waktu, seperti menjalankan npm install dan mencetak proses instalasi
dipicu setelah proses berakhir dan aliran input dan output standar (sdtio) dari proses anak telah 'close'
. Peristiwa ini berbeda dengan exit
karena beberapa proses dapat berbagi aliran stdio yang sama.
Parameter:
Pertanyaan: Apakah kode tersebut harus ada?
(Sepertinya bukan dari komentar pada kodenya) Misalnya, jika Anda menggunakan kill
untuk mematikan proses anak, apa kodenya?
parameter keluar:
kode, sinyal, jika proses anak keluar dengan sendirinya, maka code
adalah kode keluar, jika tidak maka null;
Jika proses anak diakhiri melalui suatu sinyal, maka signal
adalah sinyal untuk mengakhiri proses, jika tidak maka bernilai null.
Di antara keduanya, yang satu tidak boleh nol.
Hal yang perlu diperhatikan :
Ketika peristiwa exit
dipicu, aliran stdio dari proses anak mungkin masih terbuka. (Skenario?) Selain itu, nodejs mendengarkan sinyal SIGINT dan SIGTERM. Artinya, ketika nodejs menerima kedua sinyal ini, ia tidak akan segera keluar. Sebaliknya, ia akan melakukan beberapa pekerjaan pembersihan terlebih dahulu dan kemudian membuang kembali kedua sinyal tersebut. (Secara visual, js dapat melakukan pekerjaan pembersihan saat ini, seperti menutup database, dll.)
SIGINT
: interupsi, sinyal penghentian program, biasanya dikeluarkan ketika pengguna menekan CTRL+C, digunakan untuk memberi tahu proses latar depan untuk menghentikan proses.
SIGTERM
: terminasi, sinyal akhir program, sinyal ini dapat diblokir dan diproses, dan biasanya digunakan untuk meminta program keluar secara normal. Perintah shell kill menghasilkan sinyal ini secara default. Jika sinyal tidak dapat diputus, kami akan mencoba SIGKILL (penghentian paksa).
Ketika hal berikut terjadi, kesalahan akan dipicu. Saat kesalahan terpicu, pintu keluar mungkin terpicu atau tidak. (Hati hancur)
dipicu ketika process.send()
digunakan untuk mengirim pesan.
parameter :
message
, adalah objek json, atau nilai primitif; sendHandle
, objek net.Socket, atau objek net.Server (siswa yang familiar dengan cluster harus familiar dengan ini)
: Saat memanggil .disconnected()
, setel itu menjadi salah. Mewakili apakah ia dapat menerima pesan dari proses anak atau mengirim pesan ke proses anak.
.disconnect() : Menutup saluran IPC antara proses induk dan proses anak. Saat metode ini dipanggil, event disconnect
akan diaktifkan. Jika proses anak adalah instance node (dibuat melalui child_process.fork()), maka process.disconnect()
juga dapat dipanggil secara aktif di dalam proses anak untuk menghentikan saluran IPC.
merespons masalah single-threading. Metode multi-proses biasanya digunakan untuk mensimulasikan multi-threading.
ditempati oleh proses Node. Inti dari
mesin v8. Setelah Node dimulai, sebuah instance v8 akan dibuat
kode
单线程
, tetapi lingkungan host Javascript, baik itu Node atau browser, adalah multi-threaded.
Mengapa Javascript bersifat single-thread?
Masalah ini harus dimulai dari browser. Untuk operasi DOM di lingkungan browser, bayangkan saja jika beberapa thread beroperasi pada DOM yang sama, maka akan terjadi kekacauan menghindari konflik rendering DOM. Di lingkungan browser, thread rendering UI dan mesin eksekusi JS saling eksklusif. Ketika salah satu dijalankan, yang lain akan ditangguhkan.
process.env.UV_THREADPOOL_SIZE. = 644.
worker_threads
untuk menyediakan kemampuan multi-threading nyata ke Node.const { adalahUtas Utama, port induk, Data pekerja, threadId, Saluran Pesan, Pelabuhan Pesan, Pekerja } = memerlukan('utas_pekerja'); fungsi benang utama() { untuk (misalkan i = 0; i < 5; i++) { const pekerja = Pekerja baru(__namafile, { data pekerja: i }); pekerja.on('exit', code => { console.log(`main: pekerja berhenti dengan kode keluar ${code}`); }); pekerja.on('pesan', pesan => { console.log(`utama: terima ${msg}`); pekerja.postMessage(pesan + 1); }); } } fungsi pekerjaThread() { console.log(`pekerja: tanggal pekerja ${workerData}`); parentPort.on('pesan', pesan => { console.log(`pekerja: menerima ${msg}`); }), parentPort.postMessage(data pekerja); } jika (adalahUtas Utama) { benang utama(); } kalau tidak { benang pekerja(); }
const menegaskan = require('assert'); konstanta { Pekerja, Saluran Pesan, Pelabuhan Pesan, adalahUtas Utama, port induk } = memerlukan('utas_pekerja'); jika (adalahUtas Utama) { const pekerja = Pekerja baru(__namafile); const subsaluran = saluran pesan baru(); pekerja.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1]); subChannel.port2.on('pesan', (nilai) => { console.log('diterima:', nilai); }); } kalau tidak { parentPort.once('pesan', (nilai) => { menegaskan(nilai.di siniIsYourPort instance dari MessagePort); value.hereIsYourPort.postMessage('pekerja mengirimkan ini'); nilai.hereIsYourPort.close(); }); }
Proses adalah unit terkecil dari alokasi sumber daya, dan thread adalah unit terkecil dari penjadwalan CPU.
IPC (Komunikasi antar-proses) adalah进程间通信
Karena setiap proses memiliki ruang alamat independen setelah pembuatan, tujuan penerapan IPC adalah untuk berbagi akses ke sumber daya antar proses.
Ada banyak cara untuk mengimplementasikan IPC: pipa, antrian pesan, semafor, Soket Domain, dan Node.js diimplementasikan melalui pipa.
Faktanya, proses induk terlebih dahulu akan membuat saluran IPC dan mendengarkan IPC ini sebelum membuat proses anak, lalu membuat proses anak. Proses tersebut akan memberi tahu proses anak dan deskriptor file yang terkait dengan saluran IPC melalui variabel lingkungan ( NODE_CHANNEL_FD). Proses anak dimulai Pada saat ini, saluran IPC terhubung sesuai dengan deskriptor file untuk membuat koneksi dengan proses induk.
Pegangan adalah referensi yang dapat digunakan untuk mengidentifikasi sumber daya. Ini berisi deskriptor sumber daya file yang menunjuk ke objek.
Secara umum, ketika kita ingin memantau beberapa proses pada satu port, kita dapat mempertimbangkan untuk menggunakan agen proses utama:
Namun, solusi proksi ini akan menyebabkan setiap penerimaan permintaan dan penerusan proksi menggunakan dua deskriptor file, dan deskriptor file sistem terbatas.
Jadi mengapa menggunakan pegangan? Alasannya adalah bahwa dalam skenario aplikasi sebenarnya, membangun komunikasi IPC mungkin melibatkan skenario pemrosesan data yang lebih kompleks. Pegangan dapat diteruskan sebagai parameter opsional kedua dari metode send()
, yang berarti bahwa pengidentifikasi sumber daya dapat diteruskan secara langsung transmisi menghindari penggunaan deskriptor file yang disebabkan oleh penerusan proxy yang disebutkan di atas.
Berikut ini adalah tipe handle yang mendukung pengiriman:
Setelah proses induk dari proses yatim piatu membuat proses anak, proses induk keluar, tetapi satu atau lebih anak Proses yang sesuai dengan proses induk masih hidup. Ini diilustrasikan oleh contoh kode berikut.
# Worker.js const http = membutuhkan ('http'); server const = http.createServer ((req, res) => { res.end ('I Am Worker, PID:' + Process.pid + ', PPID:' + Process.PPID); // Catat proses pekerja saat ini PID dan Proses Induk PPID }); biarkan pekerja; process.on ('pesan', fungsi (pesan, sendHandle) { if (message === 'server') { Pekerja = SendHandle; worker.on ('connection', function (socket) { server.emit ('koneksi', soket); }); } })
; const fork = membutuhkan ('child_process'). fork; const server = membutuhkan ('net'). createServer (); server.listen (3000); const worker = fork ('worker.js'); worker.send ('server', server); Console.log ('Proses Pekerja Dibuat, PID: %S PPID: %S', Worker.pid, Process.pid); Process.exit (0); // Setelah membuat proses anak, proses utama keluar
.
Karena proses induk keluar di master.js, monitor aktivitas hanya menunjukkan proses pekerja.
Verifikasi lagi, buka antarmuka panggilan konsol, Anda dapat melihat bahwa PPID yang sesuai dengan proses pekerja 5611 adalah 1 (untuk proses init), dan telah menjadi proses yatim piatu saat ini.
Proses daemon berjalan di latar belakang dan tidak terpengaruh oleh terminal.
Siswa yang mengembangkan Node.js mungkin terbiasa dengan itu node app.js
前台运行模式
.
Jika metode proses daemon digunakan, setelah saya menjalankan node app.js
untuk memulai proses layanan di terminal ini, saya juga dapat melakukan hal -hal lain di terminal ini tanpa mempengaruhi satu sama lain.
Buat proses anak
Buat sesi baru dalam proses anak (hubungi Fungsi Sistem Setsid)
Ubah direktori kerja proses anak (seperti: "/" atau "/usr/, dll.)
Menghentikan proses induk
options.detached
Langkah
const spawn = membutuhkan ('child_process'). spawn; function startdaemon () { const daemon = spawn ('node', ['daemon.js'], { CWD: '/usr', terpisah: Benar, stdio: 'abaikan', }); Console.log ('Proses Daemon Memulai Proses Induk PID: %S, Proses Daemon PID: %S', Process.pid, Daemon.pid); daemon.unref (); } startdaemon ()
Logika pemrosesan dalam file daemon.js memulai timer dan menjalankannya setiap 10 detik sehingga sumber daya ini tidak akan keluar
.dari proses anak.
const fs = memerlukan('fs'); const {konsol} = membutuhkan ('konsol'); // Logger sederhana khusus const logger = konsol baru (fs.createWriteStream ('./ stdout.log'), fs.createWriteStream ('./ stderr.log')); setInterval (function () { Logger.log ('Daemon PID:', Process.pid, ', ppid:', Process.ppid);},
1000
*
10);
Dalam pekerjaan yang sebenarnya, kami tidak asing dengan proses daemon, seperti PM2, telur-cluster, dll. Di atas hanyalah demo sederhana untuk menjelaskan proses daemon. Proses daemon masih sangat tinggi.
5.Direktori
process.cwd()
Dari direktori proses induk, yang dapat diperoleh melalui process.chdir()
Apa
yang dilakukannya?
Hasil yang benar tidak akan diperoleh. Dalam kasus lain, modul pihak ketiga yang dirujuk dalam program juga dicari berdasarkan direktori di mana proses saat ini dimulai.
// Contoh proses.chdir ('/user/may/documents/test/') // Atur konsol direktori proses saat ini.