nodeJSおよびノンブロッキングI / O

こんばんは、親愛なる読者、


最近、ノードに関するいくつかの言及がハブで滑りました。これは、JavaScriptでWebアプリケーションを作成するための高速プラットフォームであり、今日では非常にユニークな機能、ノンブロッキングI / O(入力/出力)を備えています。

nodeJSを開始するには:


1)言語としてJavaScriptが使用されます
2)JavaScriptを実行するには、GoogleのV8エンジンが使用されます。これは、実行前にマシンコードにコンパイルされるため、非常に高速に動作します。
3)ノンブロッキングI / Oの実装には、libevとlibeioが使用されます(libevはlibeventよりも良い結果を示します)
4)ライブラリの接続を実装するためにCommonJS構文が選択されました
5)C / C ++でもモジュールを書くことができますが、それらはjsモジュールとまったく同じ方法で接続されていますが、これにより、例えば、アプリケーションのボトルネックを問題なくC ++に書き換えることができます

最終的にこの記事の執筆につながったこの点を研究する過程で、私はこの機能をうまく使うことができました。 そして、非ブロッキングI / Oはパフォーマンスと負荷抵抗に非常に非常に良い影響を与えると言えます。



3つのスキームを考えてみましょう。


1)マルチプロセッサモデル(プロセス内の各ユーザー)
2)シングルプロセスイベントループ
3)ノンブロッキングI / Oを使用したシングルプロセスイベントループ(NodeJS)

システムに1つのコアを持つプロセッサが1つだけあるとします(コアがさらにある場合は、アプリケーションの複数のインスタンスを実行できます)

次に、それぞれについて具体的に説明します。

1)マルチプロセスアプリケーション
重い負荷(多数の接続)では、各ユーザーに個別のプロセスが割り当てられ、その結果、大量のRAMが消費され、プロセスの変更はかなり高価な操作であるため、プロセッサが過負荷になるため、非常に悪い結果を示します

2)シングルプロセスイベントループ
一方では、このようなアプローチはプロセスが1つしかないため、負荷がかかった場合でも動作が向上します。つまり、プロセスを変更するために追加のRAMや追加の計算は必要ありませんが、アプリケーションでファイルを読み取るたびに、または、データベースに要求を行うと、イベントループ全体が停止し、ハードドライブまたはサーバーからの応答を待機します。この時点でプロセッサは何もしません。効率が大幅に低下します。

3)ノンブロッキングI / Oを使用したシングルプロセスイベントループ
このアプローチは、最初の2つの利点を組み合わせて、余分なメモリを消費せず、プロセスを変更するために不必要な計算を行いませんが、ファイルの読み取り中、データベースへのアクセス中など、アプリケーションはアイドル状態になりません...しかし、この方法には1つの重大な欠点があります。 このようなアプリケーションの開発は非常に困難です。 だった! しかし今、nodeJSがあります!

公式サイトの最も簡単な例を次に示します。
var sys = require ( 'sys' ) , http = require ( 'http' ) ; http. createServer ( function ( req , res ) { setTimeout ( function ( ) { res. sendHeader ( 200 , { 'Content-Type' : 'text/plain' } ) ; res. sendBody ( 'Hello World' ) ; res. finish ( ) ; } , 2000 ) ; } ) . listen ( 8000 ) ; sys. puts ( 'Server running at 127.0.0.1:8000/' ) ;
  1. var sys = require ( 'sys' ) , http = require ( 'http' ) ; http. createServer ( function ( req , res ) { setTimeout ( function ( ) { res. sendHeader ( 200 , { 'Content-Type' : 'text/plain' } ) ; res. sendBody ( 'Hello World' ) ; res. finish ( ) ; } , 2000 ) ; } ) . listen ( 8000 ) ; sys. puts ( 'Server running at 127.0.0.1:8000/' ) ;
  2. var sys = require ( 'sys' ) , http = require ( 'http' ) ; http. createServer ( function ( req , res ) { setTimeout ( function ( ) { res. sendHeader ( 200 , { 'Content-Type' : 'text/plain' } ) ; res. sendBody ( 'Hello World' ) ; res. finish ( ) ; } , 2000 ) ; } ) . listen ( 8000 ) ; sys. puts ( 'Server running at 127.0.0.1:8000/' ) ;
  3. var sys = require ( 'sys' ) , http = require ( 'http' ) ; http. createServer ( function ( req , res ) { setTimeout ( function ( ) { res. sendHeader ( 200 , { 'Content-Type' : 'text/plain' } ) ; res. sendBody ( 'Hello World' ) ; res. finish ( ) ; } , 2000 ) ; } ) . listen ( 8000 ) ; sys. puts ( 'Server running at 127.0.0.1:8000/' ) ;
  4. var sys = require ( 'sys' ) , http = require ( 'http' ) ; http. createServer ( function ( req , res ) { setTimeout ( function ( ) { res. sendHeader ( 200 , { 'Content-Type' : 'text/plain' } ) ; res. sendBody ( 'Hello World' ) ; res. finish ( ) ; } , 2000 ) ; } ) . listen ( 8000 ) ; sys. puts ( 'Server running at 127.0.0.1:8000/' ) ;
  5. var sys = require ( 'sys' ) , http = require ( 'http' ) ; http. createServer ( function ( req , res ) { setTimeout ( function ( ) { res. sendHeader ( 200 , { 'Content-Type' : 'text/plain' } ) ; res. sendBody ( 'Hello World' ) ; res. finish ( ) ; } , 2000 ) ; } ) . listen ( 8000 ) ; sys. puts ( 'Server running at 127.0.0.1:8000/' ) ;
  6. var sys = require ( 'sys' ) , http = require ( 'http' ) ; http. createServer ( function ( req , res ) { setTimeout ( function ( ) { res. sendHeader ( 200 , { 'Content-Type' : 'text/plain' } ) ; res. sendBody ( 'Hello World' ) ; res. finish ( ) ; } , 2000 ) ; } ) . listen ( 8000 ) ; sys. puts ( 'Server running at 127.0.0.1:8000/' ) ;
  7. var sys = require ( 'sys' ) , http = require ( 'http' ) ; http. createServer ( function ( req , res ) { setTimeout ( function ( ) { res. sendHeader ( 200 , { 'Content-Type' : 'text/plain' } ) ; res. sendBody ( 'Hello World' ) ; res. finish ( ) ; } , 2000 ) ; } ) . listen ( 8000 ) ; sys. puts ( 'Server running at 127.0.0.1:8000/' ) ;
  8. var sys = require ( 'sys' ) , http = require ( 'http' ) ; http. createServer ( function ( req , res ) { setTimeout ( function ( ) { res. sendHeader ( 200 , { 'Content-Type' : 'text/plain' } ) ; res. sendBody ( 'Hello World' ) ; res. finish ( ) ; } , 2000 ) ; } ) . listen ( 8000 ) ; sys. puts ( 'Server running at 127.0.0.1:8000/' ) ;
  9. var sys = require ( 'sys' ) , http = require ( 'http' ) ; http. createServer ( function ( req , res ) { setTimeout ( function ( ) { res. sendHeader ( 200 , { 'Content-Type' : 'text/plain' } ) ; res. sendBody ( 'Hello World' ) ; res. finish ( ) ; } , 2000 ) ; } ) . listen ( 8000 ) ; sys. puts ( 'Server running at 127.0.0.1:8000/' ) ;
  10. var sys = require ( 'sys' ) , http = require ( 'http' ) ; http. createServer ( function ( req , res ) { setTimeout ( function ( ) { res. sendHeader ( 200 , { 'Content-Type' : 'text/plain' } ) ; res. sendBody ( 'Hello World' ) ; res. finish ( ) ; } , 2000 ) ; } ) . listen ( 8000 ) ; sys. puts ( 'Server running at 127.0.0.1:8000/' ) ;

簡単です。スクリプトは2秒待機して、Hello Worldを送信します。 それは非常に単純なタスクのように思えますが、たとえばpythonで記述しましょう。
確立されたライブラリである竜巻(おそらく最速のもの)を使用して、次のように記述します。

Copy Source | Copy HTML
  1. #!/ usr / bin / env python
  2. tornado.httpserverをインポートする
  3. tornado.ioloopをインポートする
  4. tornado.webをインポートする
  5. 輸入時間
  6. クラス MainHandler(tornado.web.RequestHandler):
  7. def get (self):
  8. 時間の睡眠(2)
  9. 自己。 書き込み (「Hello World」)
  10. application = tornado.web.Application([
  11. (r "/"、MainHandler)、
  12. ])
  13. __name__ == "__main__"の場合:
  14. http_server = tornado.httpserver.HTTPServer(アプリケーション)
  15. http_server.listen(8888)
  16. tornado.ioloop.IOLoop.instance()。 開始 ()


また、非常に短くエレガントでした。

テスト(10人のユーザーが突然Webサーバーを使用しましたが、ApacheBenchは私ほど忍耐強くありません..):

パイソン、トルネード


 ab -n 10 -c 10 http://127.0.0.1:8888/
テストにかかった時間:20.078秒


nodeJS


 ab -n 10 -c 10 http://127.0.0.1:8000/
テストにかかった時間:2.007秒


time.sleepはブロッキング関数であるためです。つまり、Pythonのイベントループが入力出力に接続されたほとんどすべてによってブロックされるように、イベントループ全体をブロックし、上級プログラマーのみがその方法を知っているためです。またはインタープリターをブロックせずに他のアクションを実行します。これに対する決定はかなり面倒で見苦しいものです。


もちろん、2つの例は完全に異なりますが、Pythonで非同期コードを記述すると、ノード上ではすべての標準呼び出しが非同期であるという理由だけでノード上よりも多くの労力が必要になります。

私はすべてが明らかになったと思います...そして、Pythonプログラマーがスレッドを使用して私の例をすばやく書き換えて、それが正常に機能するように、コードだけが2倍大きくなり、各ファイルを要求する人を手を上げることは間違いありませんシステムまたはデータベースは別のスレッドで実行されます!

完了する代わりに


ノンブロッキング入出力は、nodeJS哲学の一部です。 ファイルの操作、TCP、HTTP、DNSの操作、システムとの通信、他のプロセスとの通信、これらすべては入出力をブロックしません。 nodeのhashlibライブラリを書いたとき、この魅力に気付きました。 ノンブロッキング関数md5_fileの作成少し実験をしました。 実際、ファイルからmd5を取得するのは非常に簡単な手順です。たとえば、ムービーのサイズは5〜15分で、結果として80%の時間がmd5の計算に費やされず、ライブラリを使用したファイルの読み取りにそれぞれ費やされます。同時に5つのフィルムからmd5を抽出します。同時に、標準ツールを使用して1つだけを抽出します。

ここで多くの有用なものを見つけることができます: nodejs

Source: https://habr.com/ru/post/J83865/


All Articles