Artikel ini akan meneroka prinsip komunikasi proses antara Node.js dan Electron, memperkenalkan cara elektron memproses komunikasi, bagaimana proses_anak dan kelompok nodejs memproses komunikasi dan memahami intipati komunikasi proses.
Mengapa bahagian hadapan perlu memahami komunikasi proses:
Medan bahagian hadapan bukan lagi sekadar menulis halaman yang dijalankan dalam penyemak imbas, tetapi juga perlu mengetahui elektron, nodej, dsb., dan kedua-dua teknologi memerlukan penguasaan komunikasi proses.
Nodejs ialah masa jalan bagi js, ia memanjangkan banyak API yang merangkumi keupayaan sistem pengendalian, termasuk API proses pembelajaran dan proses pembelajaran memerlukan pembelajaran antara mekanisme komunikasi.
Elektron ialah penyelesaian pembangunan desktop berdasarkan kromium dan nodejs Seni binanya ialah proses utama dan pelbagai proses pemaparan juga diperlukan antara kedua-dua proses ini. [Kajian yang disyorkan: "tutorial nodejs"]
Dalam artikel ini, kita akan melihat dengan lebih mendalam tentang komunikasi proses.
Artikel ini akan menerangkan perkara pengetahuan berikut:
Kod yang telah kami tulis mesti dijalankan pada sistem pengendalian Untuk menggunakan sumber perkakasan dengan lebih baik, sistem pengendalian menyokong penyelarasan berbilang program dan peruntukan sumber perkakasan. . Unit peruntukan ialah Proses, proses ini adalah proses pelaksanaan program. Sebagai contoh, rekodkan langkah mana program telah dilaksanakan, sumber perkakasan mana yang telah digunakan, port mana yang diduduki, dsb.
Proses ini termasuk kod yang akan dilaksanakan, data yang dikendalikan oleh kod dan blok kawalan proses PCB (Processing Control Block), kerana program adalah proses pelaksanaan kod pada set data, dan status proses pelaksanaan dan sumber yang dipohon Perlu direkodkan dalam struktur data (PCB). Jadi prosesnya terdiri daripada kod, data, PCB.
PCB merekodkan pid, alamat kod yang dilaksanakan, status proses (disekat, berjalan, sedia, dll.), serta semaphore, paip dan mesej baris gilir yang digunakan untuk komunikasi dan struktur data lain.
Proses dijalankan secara berterusan dari penciptaan ke kod, ke aplikasi untuk sumber perkakasan (memori, fail cakera keras, rangkaian, dll. Ia mungkin disekat di tengah). , dan proses akan dimusnahkan selepas pelaksanaan. Ini adalah kitaran hayat sesuatu proses.
Sesuatu proses adalah eksklusif untuk sumber yang diminta Setiap proses hanya boleh mengakses sumbernya sendiri. Bagaimanakah proses berkomunikasi antara satu sama lain.
Oleh kerana memori yang ada berbeza, proses yang berbeza mesti berkomunikasi melalui medium perantaraan.
Semaphore
Jika ia adalah tanda mudah, diwakili oleh nombor dan diletakkan dalam atribut PCB, ini dipanggil 信号量
, sebagai contoh, kunci boleh dilaksanakan melalui semafor.
Idea semaphore ini sering digunakan semasa menulis kod bahagian hadapan Contohnya, semasa melaksanakan pendikitan, pembolehubah penanda juga mesti ditambah.
Pipeline
Tetapi semaphore tidak boleh memindahkan data tertentu Anda perlu menggunakan kaedah lain untuk memindahkan data tertentu. Sebagai contoh, kita boleh berkomunikasi dengan membaca dan menulis fail, iaitu 管道
Jika ia adalah fail dalam ingatan, ia dipanggil paip tanpa nama dan tidak mempunyai nama fail Jika ia adalah fail pada cakera keras sebenar, ia mempunyai nama fail, yang dipanggil talian paip.
Fail perlu dibuka dahulu, kemudian dibaca dan ditulis, dan kemudian ditutup semula. Ini juga merupakan ciri saluran paip. Paip dikapsulkan berdasarkan idea fail Ia dipanggil paip kerana ia hanya boleh dibaca oleh satu proses dan ditulis oleh satu proses. Selain itu, proses sasaran juga perlu menggunakan data secara serentak, jika tidak, ia akan disekat.
Kaedah paip ini sangat mudah untuk dilaksanakan Ia adalah membaca dan menulis fail, tetapi ia hanya boleh digunakan untuk berkomunikasi antara dua proses dan hanya boleh berkomunikasi secara serentak. Malah, komunikasi segerak paip juga agak biasa, iaitu kaedah paip aliran.
Baris Gilir Mesej
Pelaksanaan saluran paip adalah mudah, tetapi komunikasi segerak agak terhad. Bagaimana jika anda ingin membuat komunikasi tak segerak? Hanya tambahkan baris gilir sebagai penimbal Ini ialah 消息队列
.
Baris gilir mesej juga merupakan komunikasi antara dua proses, tetapi ia tidak berdasarkan idea berasaskan fail Walaupun ia juga sehala, ia mempunyai sifat tak segerak dan boleh meletakkan banyak mesej dan menggunakannya semua sekali.
Memori bersama
Saluran paip dan baris gilir mesej berada di antara dua proses. Bagaimana jika terdapat berbilang proses?
Kita boleh berkomunikasi dengan cara ini dengan memohon memori yang boleh dikendalikan oleh pelbagai proses, dipanggil 共享内存
. Setiap proses boleh membaca dan menulis data ke memori ini, yang agak cekap.
Walaupun memori dikongsi adalah cekap dan boleh digunakan untuk komunikasi antara pelbagai proses, ia tidak semuanya baik kerana berbilang proses boleh membaca dan menulis, jadi anda perlu mengawal susunan itu sendiri. seperti melalui Semaphore (pembolehubah tanda) proses dikawal.
Memori yang dikongsi sesuai untuk komunikasi antara pelbagai proses tanpa melalui medium perantaraan, jadi ia lebih cekap, tetapi ia juga lebih rumit untuk digunakan.
Perkara di atas adalah hampir semua cara untuk komunikasi proses setempat.
Komunikasi proses ialah ipc (Komunikasi Antara Proses mungkin dimiliki oleh komputer yang sama, atau ia mungkin berbeza pada rangkaian proses Komputer, jadi kaedah komunikasi proses terbahagi kepada dua jenis:
Panggilan prosedur tempatan LPC (panggilan prosedur tempatan) dan panggilan prosedur jauh RPC (panggilan prosedur jauh).
Panggilan prosedur tempatan adalah kaedah komunikasi semaphore, paip, baris gilir mesej, dan memori yang dikongsi di atas Tetapi jika ia berada di rangkaian, ia mesti berkomunikasi melalui protokol rangkaian Terdapat banyak, seperti http dan websocket.
Jadi, apabila seseorang menyebut ipc, mereka bercakap tentang komunikasi proses, yang boleh dibahagikan kepada dua jenis: tempatan dan jauh.
Yang jauh dikapsulkan berdasarkan protokol rangkaian, manakala yang tempatan dikapsulkan berdasarkan semaphore, paip, baris gilir mesej dan memori dikongsi, seperti elektron dan nodej, yang akan kita bincangkan seterusnya.
elektron akan mula-mula memulakan proses utama, kemudian buat proses pemaparan melalui BrowserWindow, muatkan halaman html untuk pemaparan. Komunikasi antara kedua-dua proses adalah melalui API ipc yang disediakan oleh elektron.
ipcMain, ipcRenderer
Dalam proses utama, acara dipantau melalui kaedah on ipcMain
import { ipcMain } from 'electron'; ipcMain.on('异步事件', (event, arg) => { event.sender.send('异步事件返回', 'yyy'); })
Dalam proses pemaparan, Kaedah on ipcRenderer mendengar acara dan menghantar mesej melalui hantar
import { ipcRenderer } from 'electron'; ipcRender.on('异步事件返回', function (event, arg) { const message = `异步消息: ${arg}` }) ipcRenderer.send('异步事件', 'xxx')
API agak mudah digunakan Ini ialah API bentuk acara yang dirangkumkan oleh lapisan c dan kemudian terdedah kepada js.
Kita boleh fikir tentang mekanisme apa yang berasaskannya?
Jelas sekali terdapat tahap tertentu sifat tak segerak, dan ia adalah komunikasi antara proses ibu bapa dan anak, jadi ia dilaksanakan dalam bentuk baris gilir mesej.
jarak
Selain API berasaskan peristiwa, elektron juga menyediakan API penyeruan kaedah jauh rmi (penggunaan kaedah jauh).
sebenarnya adalah enkapsulasi lanjut mesej, iaitu memanggil kaedah yang berbeza mengikut mesej yang dihantar Dalam bentuk, ia sama seperti memanggil kaedah proses ini, tetapi sebenarnya ia dilakukan dengan menghantar mesej kepada proses lain Borang pada dasarnya adalah sama seperti ipcMain dan ipcRenderer.
Sebagai contoh, dalam proses pemaparan, api BrowserWindow yang hanya tersedia dalam proses utama dipanggil terus melalui alat kawalan jauh.
const { BrowserWindow } = require('electron').remote; let win = new BrowserWindow({ width: 800, height: 600 }); win.loadURL('https://github.com');
Untuk meringkaskan, kaedah komunikasi proses ibu bapa elektron adalah berdasarkan pengkapsulan baris gilir mesej Terdapat dua bentuk enkapsulasi, yang digunakan melalui api ipcMain dan ipcRenderer , dan yang lain adalah Ia dirangkumkan lagi ke dalam panggilan kaedah yang berbeza (rmi) Lapisan bawah juga berdasarkan mesej Ia melaksanakan kaedah jauh tetapi kelihatan seperti melaksanakan kaedah tempatan.
nodejs menyediakan API untuk mencipta proses, dengan dua modul: child_process dan cluster. Jelas sekali, satu adalah untuk penciptaan dan komunikasi proses ibu bapa-anak, dan satu lagi adalah untuk pelbagai proses.
child_process
child_process menyediakan spawn, exec, execFile dan fork API, yang digunakan untuk penciptaan proses yang berbeza:
spawn, exec
Jika anda ingin melaksanakan arahan melalui shell, gunakan spawn atau exec. Oleh kerana secara amnya melaksanakan perintah memerlukan nilai pulangan, kedua-dua API adalah berbeza dalam cara ia mengembalikan nilai.
Spawn mengembalikan strim, yang diambil melalui peristiwa data, dibahagikan lagi kepada penimbal, yang lebih mudah digunakan, tetapi mungkin melebihi maxBuffer.
const { spawn } = require('child_process'); var app = spawn('node','main.js' {env:{}}); app.stderr.on('data',function(data) { console.log('Error:',data); }); app.stdout.on('data',function(data) { console.log(data); });
Malah, exec dikapsulkan berdasarkan spwan dan boleh digunakan dalam senario mudah Kadangkala maxBuffer perlu ditetapkan.
const { exec } = require('child_process'); exec('find . -type f', { maxBuffer: 1024*1024 }(err, stdout, stderr) => { if (err) { console.error(`exec error: ${err}`); return; } console.log(stdout); });
execFile
Selain melaksanakan arahan, jika anda ingin melaksanakan fail boleh laku, gunakan api execFile:
const { execFile } = require('child_process'); const child = execFile('node', ['--version'], (error, stdout, stderr) => { if (error) { throw error; } console.log(stdout); });
fork
Dan jika anda ingin melaksanakan js, maka gunakan fork:
const { fork } = require('child_process'); const xxxProcess = fork('./xxx.js'); xxxProcess.send('111111'); xxxProcess.on('message', sum => { res.end('22222'); });
Ringkasan
Ringkas ringkasan child_process 4 API:
Jika anda ingin melaksanakan perintah shell, gunakan spawn dan exec mengembalikan strim dan exec merangkumkannya ke dalam penimbal. Kecuali exec kadangkala perlu menetapkan maxBuffer, tidak ada perbezaan.
Jika anda ingin melaksanakan fail boleh laku, gunakan execFile.
Jika anda ingin melaksanakan fail js, gunakan fork.
child_process 的进程通信
说完了 api 我们来说下 child_process 创建的子进程怎么和父进程通信,也就是怎么做 ipc。
pipe
首先,支持了 pipe,很明显是通过管道的机制封装出来的,能同步的传输流的数据。
const { spawn } = require('child_process'); const find = spawn('cat', ['./aaa.js']); const wc = spawn('wc', ['-l']); find.stdout.pipe(wc.stdin);
比如上面通过管道把一个进程的输出流传输到了另一个进程的输入流,和下面的 shell 命令效果一样:
cat ./aaa.js | wc -l
message
spawn 支持 stdio 参数,可以设置和父进程的 stdin、stdout、stderr 的关系,比如指定 pipe 或者 null。还有第四个参数,可以设置 ipc,这时候就是通过事件的方式传递消息了,很明显,是基于消息队列实现的。
const { spawn } = require('child_process'); const child = spawn('node', ['./child.js'], { stdio: ['pipe', 'pipe', 'pipe', 'ipc'] }); child.on('message', (m) => { console.log(m); }); child.send('xxxx');
而 fork 的 api 创建的子进程自带了 ipc 的传递消息机制,可以直接用。
const { fork } = require('child_process'); const xxxProcess = fork('./xxx.js'); xxxProcess.send('111111'); xxxProcess.on('message', sum => { res.end('22222'); });
cluster
cluster 不再是父子进程了,而是更多进程,也提供了 fork 的 api。
比如 http server 会根据 cpu 数启动多个进程来处理请求。
import cluster from 'cluster'; import http from 'http'; import { cpus } from 'os'; import process from 'process'; const numCPUs = cpus().length; if (cluster.isPrimary) { for (let i = 0; i < numCPUs; i++) { cluster.fork(); } } else { const server = http.createServer((req, res) => { res.writeHead(200); res.end('hello world\n'); }) server.listen(8000); process.on('message', (msg) => { if (msg === 'shutdown') { server.close(); } }); }
它同样支持了事件形式的 api,用于多个进程之间的消息传递,因为多个进程其实也只是多个父子进程的通信,子进程之间不能直接通信,所以还是基于消息队列实现的。
共享内存
子进程之间通信还得通过父进程中转一次,要多次读写消息队列,效率太低了,就不能直接共享内存么?
现在 nodejs 还是不支持的,可以通过第三方的包 shm-typed-array 来实现,感兴趣可以看一下。
https://www.npmjs.com/package/shm-typed-array
进程包括代码、数据和 PCB,是程序的一次执行的过程,PCB 记录着各种执行过程中的信息,比如分配的资源、执行到的地址、用于通信的数据结构等。
进程之间需要通信,可以通过信号量、管道、消息队列、共享内存的方式。
信号量就是一个简单的数字的标记,不能传递具体数据。
管道是基于文件的思想,一个进程写另一个进程读,是同步的,适用于两个进程。
消息队列有一定的 buffer,可以异步处理消息,适用于两个进程。
共享内存是多个进程直接操作同一段内存,适用于多个进程,但是需要控制访问顺序。
这四种是本地进程的通信方式,而网络进程则基于网络协议的方式也可以做进程通信。
进程通信叫做 ipc,本地的叫做 lpc,远程的叫 rpc。
其中,如果把消息再封装一层成具体的方法调用,叫做 rmi,效果就像在本进程执行执行另一个进程的方法一样。
electron 和 nodejs 都是基于上面的操作系统机制的封装:
elctron 支持 ipcMain 和 ipcRenderer 的消息传递的方式,还支持了 remote 的 rmi 的方式。
nodejs 有 child_process 和 cluster 两个模块和进程有关,child_process 是父子进程之间,cluster 是多个进程:
child_process 提供了用于执行 shell 命令的 spawn、exec,用于执行可执行文件的 execFile,用于执行 js 的 fork。提供了 pipe 和 message 两种 ipc 方式。
cluster 也提供了 fork,提供了 message 的方式的通信。
当然,不管封装形式是什么,都离不开操作系统提供的信号量、管道、消息队列、共享内存这四种机制。
ipc 是开发中频繁遇到的需求,希望这篇文章能够帮大家梳理清楚从操作系统层到不同语言和运行时的封装层次的脉络。
原文地址:https://juejin.cn/post/6988484297485189127
作者:zxg_神说要有光
更多编程相关知识,请访问:编程视频!!
Atas ialah kandungan terperinci Ketahui lebih lanjut tentang cara Node.js dan Electron berkomunikasi antara proses. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!