この記事では、Node.js と Electron 間のプロセス通信の原理を探り、Electron がプロセス通信を行う方法、nodejs の child_process とクラスターがプロセス通信を行う方法を紹介し、プロセス通信の本質を理解します。
フロントエンドがプロセス通信を理解する必要がある理由:
フロントエンドの分野は、もはやブラウザーで実行されるページを作成するだけではありません。ただし、Electron、nodejs などの知識も必要であり、どちらのテクノロジもプロセス通信を習得する必要があります。
Nodejs は、js のランタイムです。ブラウザとは異なり、プロセスやスレッド関連の API など、オペレーティング システムの機能をカプセル化する多くの API を拡張します。プロセス API を学習するには、プロセス間の相互作用を学習する必要があります。通信メカニズム。
Electron は chromium と Nodejs をベースとしたデスクトップ開発ソリューションです。そのアーキテクチャはメインプロセスと複数のレンダリングプロセスで構成されています。これら 2 つのプロセス間でも通信が必要です。Electron のプロセス通信メカニズムを学ぶ必要があります。 [推奨される学習: "nodejs チュートリアル "]
この記事では、プロセス通信について詳しく見ていきます。
この記事では、次の知識ポイントについて説明します:
- プロセスとは
- ローカル プロセス通信の 4 つの方法
- ipc、lpc、 rpc とは何ですか
- electron がプロセス通信を行う方法
- Nodejs の child_process とクラスターでプロセス通信を行う方法
- プロセス通信の本質
プロセス
#私たちが作成したコードはオペレーティング システム上で実行する必要があります。ハードウェア リソースをより有効に活用するために、オペレーティング システムは複数のプログラムの同時実行とハードウェア リソースの割り当てをサポートしています。割り当ての単位はプロセスであり、このプロセスがプログラムの実行プロセスになります。たとえば、プログラムが実行したステップ、どのハードウェア リソースが適用されたか、どのポートが占有されているかなどを記録します。
プログラムはデータセット上のコードの実行プロセスであるため、プロセスには、実行されるコード、コードによって操作されるデータ、およびプロセス制御ブロックPCB (Processing Control Block)が含まれます。実行プロセスのステータスと適用されたリソースをデータ構造 (PCB) に記録する必要があります。したがって、プロセスはコード、データ、PCB で構成されます。
pcb は、pid、実行されたコード アドレス、プロセスのステータス (ブロック、実行中、準備完了など)、およびセマフォ、パイプ、メッセージを記録します。通信に使用されるキューやその他のデータ構造。
プロセスは、ハードウェア リソース (メモリ、ハードディスク ファイル、ネットワークなど) の作成からアプリケーションへの継続的なコード実行までブロックされる可能性があり、最終的にプロセスは実行後は破棄されます。これがプロセスのライフサイクルです。
プロセスは、要求されたリソースに排他的にアクセスできます。各プロセスは、自分のリソースのみにアクセスできます。プロセスはどのように相互に通信しますか?
プロセス通信
利用可能なメモリはプロセスごとに異なるため、プロセスは中間媒体を介して通信する必要があります。
セマフォ
数値で表され、PCB の属性に配置される単純なマークの場合、これは ## と呼ばれます。 #Semaphore、たとえば、ロックはセマフォを通じて実装できます。
パイプライン
ただし、セマフォでは特定のデータを転送できないため、特定のデータを転送するには他の方法を使用する必要があります。たとえば、パイプラインというファイルを読み書きすることで通信できますが、メモリ内のファイルの場合は匿名パイプと呼ばれ、ファイル名はありません。ハードディスクには、名前付きパイプと呼ばれるファイル名が付いています。
Message Queue
パイプラインの実装はシンプルですが、同期通信は比較的制限されています。非同期通信を行いたい場合はどうすればよいでしょうか?バッファとしてキューを追加するだけです。これはMessage Queue です。
パイプラインとメッセージ キューは 2 つのプロセス間にあります。複数のプロセスがある場合はどうなりますか?
共有メモリと呼ばれる、複数のプロセスで操作できるメモリを申請することで、この方法で通信できます。各プロセスはこのメモリに対してデータを読み書きできるため、比較的効率的です。
ipc、rpc、lpc
プロセス通信は ipc (プロセス間通信) です。2 つのプロセスは同じコンピュータ上に存在する場合もあれば、異なるコンピュータ上に存在する場合もあります。コンピュータプロセスの通信方式は、ローカルプロシージャコールLPC(ローカルプロシージャコール)とリモートプロシージャコールRPC(リモートプロシージャコール)の2種類に分けられます。 ローカル プロシージャ コールは、上で説明したセマフォ、パイプ、メッセージ キュー、共有メモリの通信方法です。しかし、それがネットワーク上にある場合は、ネットワーク プロトコルを介して通信する必要があります。これが実際に使用されるものです。 http や websocket など、たくさんあります。 つまり、誰かが ipc について言及するとき、彼らはプロセス通信について話しているのですが、これはローカルとリモートの 2 つの方法で議論できます。 リモートのものはネットワーク プロトコルに基づいてカプセル化されますが、ローカルのものはセマフォ、パイプ、メッセージ キュー、次に説明する Electron や Nodejs などの共有メモリに基づいてカプセル化されます。electron プロセス通信
electron は最初にメイン プロセスを開始し、次に BrowserWindow を通じてレンダリング プロセスを作成し、レンダリング用の HTML ページを読み込みます。 2 つのプロセス間の通信は、electron が提供する ipc API を介して行われます。ipcMain、ipcRenderer
メイン プロセスは、ipcMain の on メソッドを通じてイベントをリッスンしますimport { ipcMain } from 'electron'; ipcMain.on('异步事件', (event, arg) => { event.sender.send('异步事件返回', 'yyy'); })レンダリング プロセスはパスしますipcRenderer on メソッドはイベントをリッスンし、send
import { ipcRenderer } from 'electron'; ipcRender.on('异步事件返回', function (event, arg) { const message = `异步消息: ${arg}` }) ipcRenderer.send('异步事件', 'xxx')を通じてメッセージを送信します。この API は比較的簡単に使用できます。これは、C レイヤーによってカプセル化され、JS に公開されるイベント形式の API です。 それはどのようなメカニズムに基づいているのか考えてみましょう。 明らかにある程度の非同期性があり、これは親プロセスと子プロセス間の通信であるため、メッセージ キューの形式で実装されます。
remote
イベント フォームの API に加えて、electron はリモート メソッド呼び出し rmi (リモート) の形式でも API を提供します。メソッドの呼び出し)。 実際には、これはメッセージをさらにカプセル化したもので、渡されたメッセージに応じてさまざまなメソッドを呼び出します。形式的には、このプロセスのメソッドを呼び出すのとまったく同じですが、実際には、メッセージを別のプロセスに送信することで実行され、その形式は基本的に ipcMain および ipcRenderer と同じです。 たとえば、レンダリング プロセスでは、メイン プロセスでのみ使用できる BrowserWindow API がリモート経由で直接呼び出されます。const { BrowserWindow } = require('electron').remote; let win = new BrowserWindow({ width: 800, height: 600 }); win.loadURL('https://github.com');electron の親子プロセス通信方式はメッセージキューのカプセル化に基づいており、カプセル化形式は 2 つあり、1 つは ipcMain と ipcRenderer の API を介して使用されるイベントメソッド、もう 1 つはイベントメソッドです。もう 1 つはさらに詳細で、さまざまなメソッド (rmi) の呼び出しにカプセル化されています。最下層もメッセージに基づいており、リモート メソッドを実行しますが、ローカル メソッドを実行しているように見えます。
nodejs
nodejs は、child_process とクラスターの 2 つのモジュールを備えたプロセスを作成するための API を提供します。明らかに、1 つは親子プロセスの作成と通信用であり、もう 1 つは複数のプロセス用です。child_process
child_process は、さまざまなプロセスの作成に使用される spawn、exec、execFile、および fork API を提供します。 spawn、execシェルを通じてコマンドを実行する場合は、spawn または exec を使用します。一般にコマンドの実行には戻り値が必要なため、2 つの API は値を返す方法が異なります。
Spawn は、データ イベントを通じて取得されるストリームを返します。exec はさらにバッファに分割され、使用が簡単になりますが、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); });
実際、exec は spwan に基づいてカプセル化されており、単純なシナリオで使用できます。場合によっては maxBuffer を設定する必要があります。
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
コマンドの実行に加えて、実行可能ファイルを実行する場合は、execFile API を使用します:
const { execFile } = require('child_process'); const child = execFile('node', ['--version'], (error, stdout, stderr) => { if (error) { throw error; } console.log(stdout); });fork
そして、js を実行したい場合は、fork を使用します。
const { fork } = require('child_process'); const xxxProcess = fork('./xxx.js'); xxxProcess.send('111111'); xxxProcess.on('message', sum => { res.end('22222'); });要約
次の 4 つの API の簡単な概要child_process:
シェル コマンドを実行する場合は、spawn と exec を使用します。spawn はストリームを返し、exec はそれをさらにバッファにカプセル化します。 exec が maxBuffer を設定する必要があることを除けば、違いはありません。
実行可能ファイルを実行する場合は、execFile を使用します。
js ファイルを実行したい場合は、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_神说要有光
更多编程相关知识,请访问:编程视频!!
以上がNode.js と Electron がプロセス間でどのように通信するかについて詳しく学ぶの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

Vercel是什么?本篇文章带大家了解一下Vercel,并介绍一下在Vercel中部署 Node 服务的方法,希望对大家有所帮助!

gm是基于node.js的图片处理插件,它封装了图片处理工具GraphicsMagick(GM)和ImageMagick(IM),可使用spawn的方式调用。gm插件不是node默认安装的,需执行“npm install gm -S”进行安装才可使用。

本篇文章带大家详解package.json和package-lock.json文件,希望对大家有所帮助!

本篇文章给大家分享一个Nodejs web框架:Fastify,简单介绍一下Fastify支持的特性、Fastify支持的插件以及Fastify的使用方法,希望对大家有所帮助!

如何用pkg打包nodejs可执行文件?下面本篇文章给大家介绍一下使用pkg将Node.js项目打包为可执行文件的方法,希望对大家有所帮助!

node怎么爬取数据?下面本篇文章给大家分享一个node爬虫实例,聊聊利用node抓取小说章节的方法,希望对大家有所帮助!

本篇文章给大家分享一个Node实战,介绍一下使用Node.js和adb怎么开发一个手机备份小工具,希望对大家有所帮助!

先介绍node.js的安装,再介绍使用node.js构建一个简单的web服务器,最后通过一个简单的示例,演示网页与服务器之间的数据交互的实现。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

VSCode Windows 64 ビットのダウンロード
Microsoft によって発売された無料で強力な IDE エディター

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

MantisBT
Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

メモ帳++7.3.1
使いやすく無料のコードエディター

SAP NetWeaver Server Adapter for Eclipse
Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

ホットトピック



