ホームページ > ウェブフロントエンド > jsチュートリアル > nodejs_node.jsにスリープ機能を実装する例

nodejs_node.jsにスリープ機能を実装する例

WBOY
リリース: 2016-05-16 16:07:48
オリジナル
3202 人が閲覧しました

nodejs の最も不快な点は、そのシングルスレッドの性質で多くのことを実行できず、CPU を集中的に使用するシナリオにはパフォーマンスが十分ではないことです。私は長い間、スレッドを操作できないことやパフォーマンスが低いという問題を解決するために、JavaScript 言語フレームワークの下でいくつかのソリューションを見つけたいと考えていました。私が最も感心したソリューションは ファイバー でしたが、ファイバーや他のソリューションに関係なく、スレッドの操作は依然として補助スレッドに依存しすぎており、ファイバーに関しては本末転倒です。 JavaScript は本質的にパフォーマンスの低下の問題を解決できません。最も厄介なことは、JavaScript 言語フレームワークではスレッド間のメッセージの受け渡しが非常に制限されていることが多く、オブジェクトを真に共有できないことです。

nodejs のアドオンメソッドは間違いなく優れており、非常に強力な柔軟性、完全な機能、ネイティブコードのパフォーマンスを備えています。簡単に言うと、nodejs が c/c モジュールを直接呼び出すことができるようになります。これは、JavaScript とネイティブの混合開発モードです。それは良いことです、なぜそれを使わないのですか?アドオンについては、今日はあまり深く話したくないのですが、私自身はあまり練習していません。次に、スリープ機能を実装し、導入として考えます。

寝る

なぜ JavaScript は本当のスリープを実装できないのでしょうか?スリープ メソッドは、オペレーティング システム カーネルにシグナルを登録し、スレッド自体がハングしている間に指定された時間が経過した後にウェイクアップ シグナルを送信します。基本的に、スレッド sleep(1000) は、オペレーティング システムに「1000 ミリ秒以内に CPU 時間を割り当てないでください」と伝えることを意味します。したがって、スリープにより、スレッドがサスペンドされたときに CPU リソースを消費しなくなることが保証されます。 JavaScript は単一のスレッドで実行され、スレッドの概念が取り消されます。当然、メインスレッドを一時停止したり中断したりする方法はありません。

JavaScript を使用してスリープを実装しようとする人もいます。例:

コードをコピー コードは次のとおりです:

関数 sleep(sleepTime) {
for(var start = new Date; new Date - start <= sleepTime; ) { }
}

これは空のループを使用してメインプロセスの実行をブロックしてスリープを実装しますが、これは明らかに実際のスリープとは程遠いものです。

それでは、実際のスリープを実装したらどうなるでしょうか?

環境の準備

開発環境

私のブログのいくつかで以前に述べたので、ここでは省略します:node.js npm、python 2.7、visual studio/x-code。

コンパイル ツール

コンパイル ツールには、node-gyp を使用する必要があります。nodejs の新しいバージョンには、node-gyp が付属していない場合は、次を実行してください。

コードをコピーします コードは次のとおりです:
npm install -g node-gyp

私には gyp の機能を勉強するエネルギーはありません。gcc などの他のコンパイラーに精通している場合は、gyp に非互換性があり、コンパイル オプションやスイッチも異なる可能性があります。実際に再利用する必要があるモジュールがある場合は、使い慣れた gcc を使用してそれをダイナミック リンク ライブラリにコンパイルし、ダイナミック リンクを使用するための少量のコードを記述することを検討できます。ライブラリを作成し、gyp を使用して、nodejs で使用できるようにコードのこの部分をコンパイルします。

プロジェクトフォルダーに入り、npm initを実行してプロジェクトを初期化します。アドオンを作成したいことをnodejsに知らせるために、package.jsonに次の内容を追加する必要があります:


コードをコピー コードは次のとおりです:
"gyp-file": true

gcc を使用したことがある場合は、makefile を覚えておく必要があります。同様に、gyp もファイルを通じてコン​​パイル設定を記述します。このファイルは、私たちがよく知っている json ファイルです。 gyp は議論の焦点では​​ないため、binding.gyp については詳しく説明しません。最も重要な構成項目のみに焦点を当てます。シンプルだが完全な binding.gyp ファイルの例を次に示します:


コードをコピー コードは次のとおりです:
{
"ターゲット": [
{
"target_name": "こんにちは",
"ソース": [ "hello.cc" ],
"include_dirs": [
" ]
}
]
}


関連する 3 つの構成項目を見てみましょう:

1.target_name: 出力モジュール名を示します。
2.sources: コンパイルする必要があるソース コードのパスを示します。これは配列です。
3.include_dirs: コンパイル プロセス中に使用されるディレクトリを示します。これらのディレクトリ内のヘッダー ファイルは、プリコンパイル ディレクティブ #include で検索できます。ここでは、パスを文字列定数として指定する代わりに、コマンド ノード -e "require('nan')" を実行します。まず、nan ライブラリについて説明します。このコマンドの出力を見てください:node_modulesnan、このコマンドは nan ライブラリのパスを返すことを意味していることがわかります。

C エンコード

OK、ソース コードが hello.cc に設定されたので、このようなファイルを作成します。事前に注意しておきたい問題があります。今回作成した c モジュールは最終的には v8 エンジンで使用されるため、API や記述方法などが v8 エンジンによって制限されます。実際には、nodejs のバージョンが異なれば、v8 エンジンの異なるバージョンが使用されます。これは、一連の C コードを使用して、nodejs の異なるバージョンを満たすことが困難であることを意味します (コンパイル プロセスを指します。コンパイルが完了すると、次のことができるはずです)。はい、Github ではバイナリ ライブラリをアップロードできないため、npm ではバイナリ ライブラリを直接アップロードしてコンパイル手順をスキップできるため、問題は比較的軽微です。

ノード 0.11 以降:

コードをコピーします コードは次のとおりです:

#include
#include

名前空間 v8 を使用;

void SleepFunc(const v8::FunctionCallbackInfo& args) {
Isolate* isolate = Isolate::GetCurrent();
HandleScope スコープ(分離);
double arg0 = args[0] -> NumberValue();
スリープ(arg0);
}

void Init(ハンドル<オブジェクト> エクスポート) {
Isolate* isolate = Isolate::GetCurrent();
exports->Set(String::NewFromUtf8(isolate, "sleep"),
FunctionTemplate::New(isolate, SleepFunc)->GetFunction());
}

NODE_MODULE(こんにちは、初期化);

ノード 0.10 以下:

コードをコピーします コードは次のとおりです:

#include
#include

名前空間 v8 を使用;

ハンドル<値> SleepFun(const Arguments& args) {
HandleScope スコープ
double arg0 = args[0] -> NumberValue();
スリープ(arg0);
戻り値scope.Close(Unknown());
}

void Init(ハンドル<オブジェクト> エクスポート) {
エクスポート->Set(String::NewSymbol("sleep"),
FunctionTemplate::New(SleepFun)->GetFunction());
}

NODE_MODULE(こんにちは、初期化);


変化がまだかなり大きいことがわかります。これらの違いを防ぐことができれば素晴らしいのですが。何か方法はありますか?私がここまで書いているのは、方法があるということを伝えるためだけです。ナン図書館に問い合わせる時が来ました。

ナン

binding.gyp で、ここで使用される nan ライブラリのパスを導入したことを思い出してください。 nan ライブラリは何のためにありますか?これは、nodejs 0.8、nodejs 0.10、nodejs 0.12、および io.js より前のアドオン間の構文の違いを保護する抽象化レイヤーを提供します。賞賛!

最初にインストールします: npm install --save nan と、nan を使用した後に同じ機能がどのように実装されるかを確認します:

コードをコピー コードは次のとおりです:

#include
名前空間 v8 を使用;

NAN_METHOD(スリープ){
NanScope();
Double arg0=args[0]->NumberValue();
スリープ(arg0);
NanReturnUnknown();
}

void Init(ハンドル<オブジェクト> エクスポート){
exports->Set(NanSymbol("sleep"), FunctionTemplate::New(Sleep)->GetFunction());
}

NODE_MODULE(こんにちは、初期化);

知っておく必要があるのは nan セットです。v8 セットについては注意する必要はありません。

下から上に見る:

コードをコピー コードは次のとおりです:

NODE_MODULE(こんにちは、初期化);

この文はアドオンの入り口を定義します。最初のパラメータは binding.gyp の target_name と一致している必要があることに注意してください。 2番目のパラメータはアドオンのエントリ関数です。

コードをコピー コードは次のとおりです:

void Init(ハンドル<オブジェクト> エクスポート){
exports->Set(NanSymbol("sleep"), FunctionTemplate::New(Sleep)->GetFunction());
}

このコードはアドオンの入力方法です。これは、exports と module という 2 つのパラメータを受け取ります。上の例では 2 番目のパラメータが省略されています。モジュールがオブジェクトを提供する場合、例のようにエクスポートに提供されるキーと値を直接指定できます。それが特別で値または関数のみを提供する場合は、次のように 2 番目のパラメーターを使用する必要があります。 NODE_SET_METHOD(モジュール , "エクスポート", foo);この例では、次のようなモジュールを出力することを意味します:

コードをコピーします コードは次のとおりです:

{
「睡眠」: 睡眠
}

スリープは関数です。スリープの定義を見てみましょう。

コードをコピー コードは次のとおりです:

NAN_METHOD(スリープ){
NanScope();
Double arg0=args[0]->NumberValue();
スリープ(arg0);
NanReturnUnknown();
}

実際にはJavaScriptで渡されたパラメータを読み込み、double型に変換してcのsleepメソッドを呼び出しています。

アドオンをコンパイルする

ここで、このモジュールのコンパイルを開始します。まず、node-gyp configure を実行してビルドの準備をします。ビルド フォルダーといくつかのファイルが生成されます。次に、node-gyp build を実行してコンパイルを開始します。この例では、最終的に hello.node ファイルが /build/Release/ ディレクトリに生成されます。これは、最終的に JavaScript によって参照できるアドオン モジュールです。

その後 C コードに変更を加えた場合は、node-gyp configure を実行する必要はなく、node-gyp build を直接実行するだけです。

nodejs は

を使用します

index.js を作成し、このモジュールの使用方法を確認してください:

コードをコピー コードは次のとおりです:

var sleep=require('./build/Release/hello.node').sleep;

console.log(新しい日付);
スリープ(1000);
console.log(新しい日付);

// 結果
// 2015 年 3 月 4 日水曜日 14:55:18 GMT 0800 (中国標準時)
// Wed Mar 04 2015 14:55:19 GMT 0800 (中国標準時)

It’s very easy, it’s exactly the same as using ordinary javascript functions.

At this point, the technical points that I want to share in this article have been explained. But...how is it different from the method provided at the beginning? I won’t take screenshots, just explain the results directly:

Since the addon method uses thread suspension, theoretically there will be no CPU usage and memory changes, and the results also verify this. Let’s look at the way JavaScript loops simulate sleep. Since the loop is always running, it’s understandable that the memory will increase a little. It’s not a big deal. Looking at the CPU usage of 25%, it seems to be quite acceptable. Is this really the case? The time has come for the truth to be revealed. The CPU of the laptop I tested is dual-core and four-threaded. Combined with the 25% CPU usage...could one of the dual-core and four-thread threads be occupied by this sleep? In fact, I found that not a single thread was locked during this period, but this is not the result of JavaScript, but the credit of Intel Hyper-Threading. Because it is said to be four threads, the essence is that the two processing cores can only be dual threads, but the CPU does a little trick of time slice cutting. For example, core cpu01 is divided into t0 and t2. Assume that in a tick after n ticks (scheduling cycle), the task will be assigned to t0, then in the next tick, the task will be assigned to t2. Therefore, from a relatively long time scale (relative to the scheduling period), the time a task runs on t0 and t2 is basically the same. So the situation presented is that the nodejs process does not occupy t0 or t2 to 100%, but takes up about 50% respectively. Since the process scheduling of Windows is relatively complex, the CPU usage fluctuates greatly. It can be predicted that if a dual-core and dual-thread CPU is used to process this script, the CPU usage will rise to 50% and one core will be stuck. If it is processed by a single-core CPU, the CPU will suddenly rise to 100%.

It seems that the CPU section talks a bit too much, and the hyper-threading section is just speculation. Just take a look.

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート