目次
プロセス
プロセス通信
nodejs
总结
ホームページ ウェブフロントエンド jsチュートリアル Node.js と Electron がプロセス間でどのように通信するかについて詳しく学ぶ

Node.js と Electron がプロセス間でどのように通信するかについて詳しく学ぶ

Jul 26, 2021 am 10:11 AM
electron node.js プロセスコミュニケーション

この記事では、Node.js と Electron 間のプロセス通信の原理を探り、Electron がプロセス通信を行う方法、nodejs の child_process とクラスターがプロセス通信を行う方法を紹介し、プロセス通信の本質を理解します。

Node.js と Electron がプロセス間でどのように通信するかについて詳しく学ぶ

フロントエンドがプロセス通信を理解する必要がある理由:

フロントエンドの分野は、もはやブラウザーで実行されるページを作成するだけではありません。ただし、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 で構成されます。

Node.js と Electron がプロセス間でどのように通信するかについて詳しく学ぶ

pcb は、pid、実行されたコード アドレス、プロセスのステータス (ブロック、実行中、準備完了など)、およびセマフォ、パイプ、メッセージを記録します。通信に使用されるキューやその他のデータ構造。

Node.js と Electron がプロセス間でどのように通信するかについて詳しく学ぶ

プロセスは、ハードウェア リソース (メモリ、ハードディスク ファイル、ネットワークなど) の作成からアプリケーションへの継続的なコード実行までブロックされる可能性があり、最終的にプロセスは実行後は破棄されます。これがプロセスのライフサイクルです。

プロセスは、要求されたリソースに排他的にアクセスできます。各プロセスは、自分のリソースのみにアクセスできます。プロセスはどのように相互に通信しますか?

プロセス通信

利用可能なメモリはプロセスごとに異なるため、プロセスは中間媒体を介して通信する必要があります。

セマフォ

数値で表され、PCB の属性に配置される単純なマークの場合、これは ## と呼ばれます。 #Semaphore、たとえば、ロックはセマフォを通じて実装できます。

このセマフォのアイデアは、フロントエンド コードを記述するときによく使用されます。たとえば、スロットリングを実装する場合は、マーク変数も追加する必要があります。

パイプライン

ただし、セマフォでは特定のデータを転送できないため、特定のデータを転送するには他の方法を使用する必要があります。たとえば、

パイプラインというファイルを読み書きすることで通信できますが、メモリ内のファイルの場合は匿名パイプと呼ばれ、ファイル名はありません。ハードディスクには、名前付きパイプと呼ばれるファイル名が付いています。

ファイルは最初に開いてから読み取りと書き込みを行ってから閉じる必要がありますが、これはパイプラインの特性でもあります。パイプはファイルの概念に基づいてカプセル化されており、1 つのプロセスでのみ読み取り、1 つのプロセスで書き込むことができるため、パイプと呼ばれます。一方向 (半二重) です。さらに、ターゲット プロセスはデータを同期的に消費する必要もあります。そうしないとブロックされてしまいます。

このパイプ メソッドは実装が非常に簡単で、ファイルの読み取りと書き込みを行いますが、2 つのプロセス間の通信にのみ使用でき、同期通信のみが可能です。実際、ストリームのパイプメソッドであるパイプの同期通信も非常に一般的です。

Message Queue

パイプラインの実装はシンプルですが、同期通信は比較的制限されています。非同期通信を行いたい場合はどうすればよいでしょうか?バッファとしてキューを追加するだけです。これは

Message Queue です。

メッセージ キューも 2 つのプロセス間の通信ですが、ファイルベースの考え方に基づいたものではなく、やはり一方向ですが、ある種の非同期的な性質があり、大量のメッセージを入れることができます。そしてそれらを一度にすべて消費します。 ############共有メモリ#########

パイプラインとメッセージ キューは 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(&#39;hello world\n&#39;);
  })
  
  server.listen(8000);
  
  process.on(&#39;message&#39;, (msg) => {
    if (msg === &#39;shutdown&#39;) {
       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 サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

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

Node V8 エンジンのメモリと GC の詳細な図による説明 Node V8 エンジンのメモリと GC の詳細な図による説明 Mar 29, 2023 pm 06:02 PM

この記事では、NodeJS V8 エンジンのメモリとガベージ コレクター (GC) について詳しく説明します。

Nodeのメモリ制御に関する記事 Nodeのメモリ制御に関する記事 Apr 26, 2023 pm 05:37 PM

ノンブロッキングおよびイベント駆動に基づいて構築されたノード サービスには、メモリ消費量が少ないという利点があり、大量のネットワーク リクエストの処理に非常に適しています。大量のリクエストを前提として、「メモリ制御」に関する問題を考慮する必要があります。 1. V8 のガベージ コレクション メカニズムとメモリ制限 Js はガベージ コレクション マシンによって制御されます

最適な Node.js Docker イメージを選択する方法について話しましょう。 最適な Node.js Docker イメージを選択する方法について話しましょう。 Dec 13, 2022 pm 08:00 PM

ノード用の Docker イメージの選択は些細なことのように思えるかもしれませんが、イメージのサイズと潜在的な脆弱性は、CI/CD プロセスとセキュリティに大きな影響を与える可能性があります。では、最適な Node.js Docker イメージを選択するにはどうすればよいでしょうか?

Node.js 19 が正式リリースされました。その 6 つの主要な機能についてお話しましょう。 Node.js 19 が正式リリースされました。その 6 つの主要な機能についてお話しましょう。 Nov 16, 2022 pm 08:34 PM

Node 19 が正式リリースされましたので、この記事では Node.js 19 の 6 つの主要な機能について詳しく説明します。

Node の File モジュールについて詳しく説明しましょう Node の File モジュールについて詳しく説明しましょう Apr 24, 2023 pm 05:49 PM

ファイル モジュールは、ファイルの読み取り/書き込み/開く/閉じる/削除の追加など、基礎となるファイル操作をカプセル化したものです。ファイル モジュールの最大の特徴は、すべてのメソッドが **同期** と ** の 2 つのバージョンを提供することです。 asynchronous**、sync サフィックスが付いているメソッドはすべて同期メソッドであり、持たないメソッドはすべて異種メソッドです。

Nodeのイベントループについて話しましょう Nodeのイベントループについて話しましょう Apr 11, 2023 pm 07:08 PM

イベント ループは Node.js の基本的な部分であり、メイン スレッドがブロックされていないことを確認することで非同期プログラミングが可能になります。イベント ループを理解することは、効率的なアプリケーションを構築するために重要です。次の記事では、Node のイベント ループについて詳しく説明します。お役に立てれば幸いです。

Node.js の GC (ガベージ コレクション) メカニズムについて話しましょう Node.js の GC (ガベージ コレクション) メカニズムについて話しましょう Nov 29, 2022 pm 08:44 PM

Node.js はどのように GC (ガベージ コレクション) を行うのでしょうか?次の記事で詳しく説明します。

pkg を使用して Node.js プロジェクトを実行可能ファイルにパッケージ化する方法について説明します。 pkg を使用して Node.js プロジェクトを実行可能ファイルにパッケージ化する方法について説明します。 Dec 02, 2022 pm 09:06 PM

Nodejs実行可能ファイルをpkgでパッケージ化するにはどうすればよいですか?次の記事では、pkg を使用して Node プロジェクトを実行可能ファイルにパッケージ化する方法を紹介します。

See all articles