SlideShare a Scribd company logo
1 of 28
そうだったのか! よくわかる
   process.nextTick()
 Node.jsのイベントループを理解する




   IIJ 大津 繁樹 (@jovi0608)
        2012年6月28日
     東京Node学園6時限目
Nodeの歩み(参考)
2007/10 libev公開           2010/08 nodejs_jp開始
2008/05 libeio公開          2010/09 no.de開始
2009/09 Google V8公開       2010/11 Joyent管轄へ
2009/02 ry Node開発開始       2011/02 node-v0.4.0リリース
2009/05 node-v0.0.1リリース   2011/03 東京Node学園#1
2009/06 nodejs ML開始       2011/10 東京Node学園祭
2009/10 npm公開             2011/11 node-v0.6.0リリース
2009/11 JSConf EU ry発表    2011/12 Azureサポート
2010/04 Herokuサポート        2012/01 isaacs管理へ
2010/08 node-v0.2.0リリース   2012/06 node-v0.8.0リリース
今日の話
•   Nodeのイベントループとは
•   process.nextTickとは
•   node-devでの大論争
•   今後どうなる?
•   process.nextTickの正しい使
    い方

おそらく世界初?の
Node-v0.8ベースでイベント
ループを解説
(libuvの大幅な変更に追随)
(注: 説明はLinuxが対象です。)
Nodeのイベントループとは、

• Node の心臓


  イベントループが終了したら
  Node は死にます。
Nodeのイベントループの正体




  Node が起動する時に uv_run() が呼
  ばれます。(src/node.cc:2910)




https://github.com/joyent/node/blob/v0.8.0-release/deps/uv/src/unix/core.c#L265
イベントループが回り続けるには




                              アクティブな handle/req がなけれ
                                       ば
                                 イベントループが終了

https://github.com/joyent/node/blob/v0.8.0-release/deps/uv/src/unix/core.c#L252-261
handle と req の違い
• handle
  – I/O が発生してない時でもイベントループを
    維持
  – (例) server.listen()



• req
  – I/Oが発生している時だけイベントループを
    維持
  – (例) http.get()
handle と req の種類
              handle                       req
ASYNC        非同期ジョブの操作      CONNECT       stream接続
CHECK        ループの最後の操作      WRITE         stream書き込み
FS_EVENT     ファイルイベント操作     SHUTDOWN      stream停止
FS_POLL      statの問い合わせ操作   UDP_SEND      udp 送信
IDLE         アイドルの時の操作      FS            ファイル操作
NAMED_PIPE   名前付きパイプの操作     WORK          ワーカスレッド
POLL         fdイベントの操作      GETADDRINFO   アドレス情報取得
PREPARE      ループの最初の操作
PROCESS      プロセスの操作
TCP          TCPの操作
                                      後で見て
TIMER        タイマー操作                   おいて下
TTY
UDP
             TTYPの操作
             UDPの操作
                                       さい。
実際のコードでは、(その1)
var http = require('http');         アクティブ
                                     ハンドル
var server = http.createServer();      0




 アクティブハンドルが無いからNode終了
実際のコードでは、(その2)
var http = require('http');
var server = http.createServer();
                                アクティブ
server.listen(1234);           ハンドル追加
                               (+1)




 アクティブハンドルが作成されNode
 は終了しない。実際は epoll wait (Linux)して
実際のコードでは、(その3)
var http = require('http');
var server = http.createServer();
server.listen(1234, function() {
                            アクティブ
 server.close();          ハンドル削除
                             (+1-1=0)
});



アクティブハンドルがすぐ無効化される
のでNode終了
イベントループの中身
  7つのステップ

      1. 時刻更新
      2. タイマー実行
      3. アイドル実行
      4. Prepare実行
      5. I/Oイベント実行
         (libev)
      6. Check実行
      7. ハンドル終了
Node-v0.8イベントループ概要
                             終わり     始まり
                                                    setTimeout()

nextTick()                            1:時刻更新
                7:ハンドル終了

         6:run_check                       2:run_timers

コールバッ
                             イベントループ                 nextTick()
  ク                           一周(Tick)                    ユーザ
             5:poll                          3:run_idle   プログラム


                                   4:run_prepare
        libev+kernel
       epoll: Linux                                  nextTick()
       kqueue: BSD
       event port: Solaris
                              (注: ユーザプログラムは 3: run_idle から始まる
イベントループを止めてはいけない!
                              終わり    始まり
                                                    setTimeout()

 nextTick()                           1:時刻更新
                 7:ハンドル終了

          6:run_check     2:run_timers
                   こんなコードはダメ! while(1)
 コールバッ
   ク                while(1) {
                      console.log(‘hoge’);
             5:poll }                      3:run_idle
                                                  ずっとここ
         libev+kernel                             で止まる!
                                    4:run_prepare
        epoll: Linux
        kqueue: BSD                                  nextTick()
        event port: Solaris
                              (注: ユーザプログラムは 3: run_idle から始まる。
なぜ3カ所も nextTick() があるの?
理由1:呼び出し順番
setTimeout(function(){
  console.log(‘3:foo’);
                                    $ node tick-order.js
}, 0);
                                    1:piyo
process.nextTick(function() {
                                    2:hoge
  console.log(‘2:hoge’);
                                    3:foo
});
console.log(‘1:piyo’);



setTimeout() より process.nextTick() が先に呼ばれる
                            (注: 将来仕様が変わる可能性があります。)
理由1:呼び出し順番
                         終わり     始まり
                                                  setTimeout()
                                               console.log(‘3:foo’)
  nextTick()                      1:時刻更新
                 7:ハンドル終了

           6:run_check                 2:run_timers
                                             console.log(‘1:piyo’)

  コールバッ
                        イベントループ                    nextTick()
    ク                    一周(Tick)
               5:poll                    3:run_idle

                               4:run_prepare
                                               console.log(‘2:hoge’)
                                                    nextTick()

(注: ユーザプログラムは 3: run_idle から始まる。)
理由2:入れ子の呼び出し順番
process.nextTick(function() {
 setTimeout(function(){
    console.log(‘4:foo');
                                  $ node tick-order2.js
 }, 0);
                                  1:piyo
 process.nextTick(function() {
                                  2:bar
    console.log(‘3:hoge');
                                  3:hoge
 });
                                  4:foo
 console.log(‘2:bar');
});
console.log(‘1:piyo’);
process.nextTick() のスコープ内でも setTimeout()
より process.nextTick() が先に呼ばれる
                          (注: 将来仕様が変わる可能性があります。)
理由2:入れ子の呼び出し順番
                            終わり      始まり
console.log(‘3:hoge’)                                 setTimeout()
                                                   console.log(‘4:foo’)
    nextTick()                        1:時刻更新
                        7:ハンドル終了

             6:run_check                   2:run_timers
                                                 console.log(‘1:piyo’)

   コールバッ
                           イベントループ                     nextTick()
     ク                      一周(Tick)
                 5:poll                      3:run_idle

                                   4:run_prepare
                                                   console.log(‘2:bar’)
                                                        nextTick()

(注: ユーザプログラムは3: run_idleから始まる。)
process.nextTick()の説明(マニュアルより)
    イベントループの次以降のループでコールバッ
    クを呼び出します。 これは setTimeout(fn, 0) の
    単純なエイリアスではなく、 はるかに効率的で
    す。
for (var i = 0; i < 1024*1024; i++) {       処理時間
  process.nextTick(function (){
   Math.sqrt(i); } );                   0.360u 0.072s 0:00.44 97.7%
}
                                            約5倍の差
for (var i = 0; i < 1024 * 1024; i++) {
  setTimeout(function () {
    Math.sqrt(i) }, 0);                 1.700u 0.800s 0:02.51 99.6%
}
       おそらくリンクリストの生成と時刻取得のオーバヘッドによるものだろう(未
node-v0.9に向けて isaacs からの提案
• process.nextTick()でイベントハンドラを追加するのはよくやること
  だけど
  次のイベントループでハンドラが登録されるまでの間にイベントが
  発生したりするとI/Oの取りこぼしが起きてしまう。
• 次のイベントが発生する前に確実にハンドラを登録をするために、
  V8でJSを実行した直後に process.nextTick() に登録された関数を全部
  実行するようにしたい。
• 再帰処理とかの展開もそこで行うので次のようなコードでは
  setTimeout() は起動しなくなるよ。
          setTimeout(function() {
           console.log('timeout');
          }, 1000);
          process.nextTick(function f() {
           process.nextTick(f);
          });
node-devでの大論争
      推進派                  擁護派
• 今までの動作がそもそもおか      • 別のAPIにすればいいじゃない
  しかった。正しい動作に変え        か
  るだけ                • 実際にコード変更するのがど
• CPU処理の分散のために再帰を      んなに大変か
  使うのは悪いこと、child     • どうせ今さら何言っても聞き
  process を使え          入れてくれないだろう
• idle用リスナの用途に再帰を使
  うのはわからんでもないが、
  setTimeoutを使え
• API名を変えるのはもう遅い
• 実際にI/Oの取りこぼしでバグ
  が出ている。この変更でそれ
  を直すのが優先する
今後どうなるのか(想像)
                                   終わり     始まり
                                                          setTimeout()
                                            1:時刻更新
                      7:ハンドル終了
                                                                nextTick()
nextTick()                                       2:run_timers    全展開
 全展開
               6:run_check

  コールバッ
                                   イベントループ
    ク                               一周(Tick)
                   5:poll                          3:run_idle

                                         4:run_prepare
             libev+kernel
             epoll: Linux
             kqueue: BSD
             event port: Solaris
                                         再帰は一定回数繰り返したら遅延させるかも
process.nextTickの正しい使い方
var events = require('events');
var util = require('util');                 非同期イ
function Hoge() {                           ベントの
  var self = this;                           生成
  process.nextTick(function() {
    self.emit('foo');
  });
}
util.inherits(Hoge, events.EventEmitter);
var hoge = new Hoge();
hoge.on('foo', function() {
  console.log('foo event emitted');
});
process.nextTickの正しい使い方
var events = require('events');
var util = require('util');
function Hoge(cb) {                         非同期コール
  if(cb) {                                  バックの呼び出
    process.nextTick(function() {
     cb();                                     し
    });
  }
}
util.inherits(Hoge, events.EventEmitter);
Hoge.prototype.setfoo = function(arg) {
  this.foo = arg;
};
var hoge = new Hoge(function() {
  hoge.setfoo('bar');
  console.log(hoge.foo);
});
process.nextTickの再帰を避ける
var cluster = require('cluster');
if (cluster.isMaster) {                  CPU消費処理は
  var worker = cluster.fork();            子プロセスで
  worker.on('message', function(msg) {
    console.log(msg);
  });
} else {
  //子プロセス
  while(1) {
    process.send(‘hoge’);
  }
}
まとめ
• Node のイベントループの仕組みを良く理解
  した上でイベントループを止めないことを意
  識してコードを書きましょう。
• process.nextTick() は、
 – 非同期イベントの発生
 – 非同期コールバックの実行
 の用途で使いましょう。
• CPUを消費する処理には、child process を利
  用しましょう。
• node-v0.9 では process.nextTick()の動作仕様
  が変わる予定です。

More Related Content

What's hot

マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!mosa siru
 
オブジェクト指向プログラミングのためのモデリング入門
オブジェクト指向プログラミングのためのモデリング入門オブジェクト指向プログラミングのためのモデリング入門
オブジェクト指向プログラミングのためのモデリング入門増田 亨
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」Takuto Wada
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話Koichiro Matsuoka
 
冬のLock free祭り safe
冬のLock free祭り safe冬のLock free祭り safe
冬のLock free祭り safeKumazaki Hiroki
 
PostgreSQLアンチパターン
PostgreSQLアンチパターンPostgreSQLアンチパターン
PostgreSQLアンチパターンSoudai Sone
 
GoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホンGoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホンAkihiko Horiuchi
 
O/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐO/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐkwatch
 
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Taku Miyakawa
 
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
今こそ知りたいSpring Web(Spring Fest 2020講演資料)今こそ知りたいSpring Web(Spring Fest 2020講演資料)
今こそ知りたいSpring Web(Spring Fest 2020講演資料)NTT DATA Technology & Innovation
 
フロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjugフロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjugItsuki Kuroda
 
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?Yoshitaka Kawashima
 
PHP-FPM の子プロセス制御方法と設定をおさらいしよう
PHP-FPM の子プロセス制御方法と設定をおさらいしようPHP-FPM の子プロセス制御方法と設定をおさらいしよう
PHP-FPM の子プロセス制御方法と設定をおさらいしようShohei Okada
 
コンテナにおけるパフォーマンス調査でハマった話
コンテナにおけるパフォーマンス調査でハマった話コンテナにおけるパフォーマンス調査でハマった話
コンテナにおけるパフォーマンス調査でハマった話Yuta Shimada
 
オブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメオブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメYoji Kanno
 
MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法Tetsutaro Watanabe
 
3週連続DDDその1 ドメイン駆動設計の基本を理解する
3週連続DDDその1  ドメイン駆動設計の基本を理解する3週連続DDDその1  ドメイン駆動設計の基本を理解する
3週連続DDDその1 ドメイン駆動設計の基本を理解する増田 亨
 
Where狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキーWhere狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキーyoku0825
 
モジュールの凝集度・結合度・インタフェース
モジュールの凝集度・結合度・インタフェースモジュールの凝集度・結合度・インタフェース
モジュールの凝集度・結合度・インタフェースHajime Yanagawa
 
コンテナネットワーキング(CNI)最前線
コンテナネットワーキング(CNI)最前線コンテナネットワーキング(CNI)最前線
コンテナネットワーキング(CNI)最前線Motonori Shindo
 

What's hot (20)

マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
 
オブジェクト指向プログラミングのためのモデリング入門
オブジェクト指向プログラミングのためのモデリング入門オブジェクト指向プログラミングのためのモデリング入門
オブジェクト指向プログラミングのためのモデリング入門
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
 
冬のLock free祭り safe
冬のLock free祭り safe冬のLock free祭り safe
冬のLock free祭り safe
 
PostgreSQLアンチパターン
PostgreSQLアンチパターンPostgreSQLアンチパターン
PostgreSQLアンチパターン
 
GoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホンGoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホン
 
O/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐO/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐ
 
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
 
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
今こそ知りたいSpring Web(Spring Fest 2020講演資料)今こそ知りたいSpring Web(Spring Fest 2020講演資料)
今こそ知りたいSpring Web(Spring Fest 2020講演資料)
 
フロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjugフロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjug
 
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?
 
PHP-FPM の子プロセス制御方法と設定をおさらいしよう
PHP-FPM の子プロセス制御方法と設定をおさらいしようPHP-FPM の子プロセス制御方法と設定をおさらいしよう
PHP-FPM の子プロセス制御方法と設定をおさらいしよう
 
コンテナにおけるパフォーマンス調査でハマった話
コンテナにおけるパフォーマンス調査でハマった話コンテナにおけるパフォーマンス調査でハマった話
コンテナにおけるパフォーマンス調査でハマった話
 
オブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメオブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメ
 
MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法
 
3週連続DDDその1 ドメイン駆動設計の基本を理解する
3週連続DDDその1  ドメイン駆動設計の基本を理解する3週連続DDDその1  ドメイン駆動設計の基本を理解する
3週連続DDDその1 ドメイン駆動設計の基本を理解する
 
Where狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキーWhere狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキー
 
モジュールの凝集度・結合度・インタフェース
モジュールの凝集度・結合度・インタフェースモジュールの凝集度・結合度・インタフェース
モジュールの凝集度・結合度・インタフェース
 
コンテナネットワーキング(CNI)最前線
コンテナネットワーキング(CNI)最前線コンテナネットワーキング(CNI)最前線
コンテナネットワーキング(CNI)最前線
 

Similar to そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する

イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化Gosuke Miyashita
 
Boost9 session
Boost9 sessionBoost9 session
Boost9 sessionfreedom404
 
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)Hiraku Toyooka
 
システムパフォーマンス勉強会#5
システムパフォーマンス勉強会#5システムパフォーマンス勉強会#5
システムパフォーマンス勉強会#5shingo suzuki
 
PHPとシグナル、その裏側
PHPとシグナル、その裏側PHPとシグナル、その裏側
PHPとシグナル、その裏側do_aki
 
PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門Yosuke Onoue
 
Unixカーネルの設計 7 プロセスの制御
Unixカーネルの設計 7 プロセスの制御Unixカーネルの設計 7 プロセスの制御
Unixカーネルの設計 7 プロセスの制御Norito Agetsuma
 
Node-v0.12の新機能について
Node-v0.12の新機能についてNode-v0.12の新機能について
Node-v0.12の新機能についてshigeki_ohtsu
 
軽量EvernoteクライアントSmartEverにおけるアプリ高速化の工夫と課題
軽量EvernoteクライアントSmartEverにおけるアプリ高速化の工夫と課題軽量EvernoteクライアントSmartEverにおけるアプリ高速化の工夫と課題
軽量EvernoteクライアントSmartEverにおけるアプリ高速化の工夫と課題Makoto Setoh
 
Spmv9forpublic
Spmv9forpublicSpmv9forpublic
Spmv9forpublicT2C_
 
Continuation with Boost.Context
Continuation with Boost.ContextContinuation with Boost.Context
Continuation with Boost.ContextAkira Takahashi
 
MINCS – containers in the shell script
MINCS – containers in the shell scriptMINCS – containers in the shell script
MINCS – containers in the shell scriptMasami Hiramatsu
 
ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)Shinichi Awamoto
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチMasami Ichikawa
 
Webサーバ勉強会_#1_108-114:ログとか
Webサーバ勉強会_#1_108-114:ログとかWebサーバ勉強会_#1_108-114:ログとか
Webサーバ勉強会_#1_108-114:ログとかDai Utsui
 
関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会Koichi Sakata
 
Pythonによる並列プログラミング -GPGPUも-
Pythonによる並列プログラミング   -GPGPUも- Pythonによる並列プログラミング   -GPGPUも-
Pythonによる並列プログラミング -GPGPUも- Yusaku Watanabe
 

Similar to そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する (20)

イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化
 
Rの高速化
Rの高速化Rの高速化
Rの高速化
 
Boost9 session
Boost9 sessionBoost9 session
Boost9 session
 
Boost Tour 1.50.0 All
Boost Tour 1.50.0 AllBoost Tour 1.50.0 All
Boost Tour 1.50.0 All
 
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
 
システムパフォーマンス勉強会#5
システムパフォーマンス勉強会#5システムパフォーマンス勉強会#5
システムパフォーマンス勉強会#5
 
PHPとシグナル、その裏側
PHPとシグナル、その裏側PHPとシグナル、その裏側
PHPとシグナル、その裏側
 
SystemV IPC
SystemV IPCSystemV IPC
SystemV IPC
 
PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門
 
Unixカーネルの設計 7 プロセスの制御
Unixカーネルの設計 7 プロセスの制御Unixカーネルの設計 7 プロセスの制御
Unixカーネルの設計 7 プロセスの制御
 
Node-v0.12の新機能について
Node-v0.12の新機能についてNode-v0.12の新機能について
Node-v0.12の新機能について
 
軽量EvernoteクライアントSmartEverにおけるアプリ高速化の工夫と課題
軽量EvernoteクライアントSmartEverにおけるアプリ高速化の工夫と課題軽量EvernoteクライアントSmartEverにおけるアプリ高速化の工夫と課題
軽量EvernoteクライアントSmartEverにおけるアプリ高速化の工夫と課題
 
Spmv9forpublic
Spmv9forpublicSpmv9forpublic
Spmv9forpublic
 
Continuation with Boost.Context
Continuation with Boost.ContextContinuation with Boost.Context
Continuation with Boost.Context
 
MINCS – containers in the shell script
MINCS – containers in the shell scriptMINCS – containers in the shell script
MINCS – containers in the shell script
 
ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)ラボユース最終成果報告会(Web公開版)
ラボユース最終成果報告会(Web公開版)
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチ
 
Webサーバ勉強会_#1_108-114:ログとか
Webサーバ勉強会_#1_108-114:ログとかWebサーバ勉強会_#1_108-114:ログとか
Webサーバ勉強会_#1_108-114:ログとか
 
関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会関ジャバ JavaOne Tokyo 2012報告会
関ジャバ JavaOne Tokyo 2012報告会
 
Pythonによる並列プログラミング -GPGPUも-
Pythonによる並列プログラミング   -GPGPUも- Pythonによる並列プログラミング   -GPGPUも-
Pythonによる並列プログラミング -GPGPUも-
 

More from shigeki_ohtsu

Node最新トピックス
Node最新トピックスNode最新トピックス
Node最新トピックスshigeki_ohtsu
 
SSL/TLSの基礎と最新動向
SSL/TLSの基礎と最新動向SSL/TLSの基礎と最新動向
SSL/TLSの基礎と最新動向shigeki_ohtsu
 
HTTP/2の現状とこれから
HTTP/2の現状とこれからHTTP/2の現状とこれから
HTTP/2の現状とこれからshigeki_ohtsu
 
Node-v0.12のTLSを256倍使いこなす方法
Node-v0.12のTLSを256倍使いこなす方法Node-v0.12のTLSを256倍使いこなす方法
Node-v0.12のTLSを256倍使いこなす方法shigeki_ohtsu
 
Technical Overview of QUIC
Technical  Overview of QUICTechnical  Overview of QUIC
Technical Overview of QUICshigeki_ohtsu
 
httpbis interim@チューリッヒ レポート
httpbis interim@チューリッヒ レポートhttpbis interim@チューリッヒ レポート
httpbis interim@チューリッヒ レポートshigeki_ohtsu
 
第43回HTML5とか勉強会 SPDY/QUICデモ
第43回HTML5とか勉強会 SPDY/QUICデモ第43回HTML5とか勉強会 SPDY/QUICデモ
第43回HTML5とか勉強会 SPDY/QUICデモshigeki_ohtsu
 
HTTP/2.0がもたらす Webサービスの進化(後半)
HTTP/2.0がもたらすWebサービスの進化(後半)HTTP/2.0がもたらすWebサービスの進化(後半)
HTTP/2.0がもたらす Webサービスの進化(後半)shigeki_ohtsu
 
HTTP/2.0 HPAC-03 エンコーディング手法 by tatsuhiro_t
HTTP/2.0 HPAC-03 エンコーディング手法 by tatsuhiro_tHTTP/2.0 HPAC-03 エンコーディング手法 by tatsuhiro_t
HTTP/2.0 HPAC-03 エンコーディング手法 by tatsuhiro_tshigeki_ohtsu
 
httpbis interim@シアトル レポート (第2回HTTP/2.0接続試験)
httpbis interim@シアトル レポート(第2回HTTP/2.0接続試験)httpbis interim@シアトル レポート(第2回HTTP/2.0接続試験)
httpbis interim@シアトル レポート (第2回HTTP/2.0接続試験)shigeki_ohtsu
 
Node の HTTP/2.0 モジュール iij-http2 の実装苦労話
Node の HTTP/2.0 モジュール iij-http2 の実装苦労話Node の HTTP/2.0 モジュール iij-http2 の実装苦労話
Node の HTTP/2.0 モジュール iij-http2 の実装苦労話shigeki_ohtsu
 
httpbis interim とhttp2.0相互接続試験の話
httpbis interim とhttp2.0相互接続試験の話httpbis interim とhttp2.0相互接続試験の話
httpbis interim とhttp2.0相互接続試験の話shigeki_ohtsu
 
Node.js で SPDYのベンチマーク体験サイトを作りました
Node.js で SPDYのベンチマーク体験サイトを作りましたNode.js で SPDYのベンチマーク体験サイトを作りました
Node.js で SPDYのベンチマーク体験サイトを作りましたshigeki_ohtsu
 
SPDYの中身を見てみよう
SPDYの中身を見てみようSPDYの中身を見てみよう
SPDYの中身を見てみようshigeki_ohtsu
 
node-gypを使ったネイティブモジュールの作成
node-gypを使ったネイティブモジュールの作成node-gypを使ったネイティブモジュールの作成
node-gypを使ったネイティブモジュールの作成shigeki_ohtsu
 

More from shigeki_ohtsu (19)

Node最新トピックス
Node最新トピックスNode最新トピックス
Node最新トピックス
 
TLS, HTTP/2演習
TLS, HTTP/2演習TLS, HTTP/2演習
TLS, HTTP/2演習
 
HTTP/2, QUIC入門
HTTP/2, QUIC入門HTTP/2, QUIC入門
HTTP/2, QUIC入門
 
SSL/TLSの基礎と最新動向
SSL/TLSの基礎と最新動向SSL/TLSの基礎と最新動向
SSL/TLSの基礎と最新動向
 
HTTP/2の現状とこれから
HTTP/2の現状とこれからHTTP/2の現状とこれから
HTTP/2の現状とこれから
 
Node-v0.12のTLSを256倍使いこなす方法
Node-v0.12のTLSを256倍使いこなす方法Node-v0.12のTLSを256倍使いこなす方法
Node-v0.12のTLSを256倍使いこなす方法
 
Technical Overview of QUIC
Technical  Overview of QUICTechnical  Overview of QUIC
Technical Overview of QUIC
 
httpbis interim@チューリッヒ レポート
httpbis interim@チューリッヒ レポートhttpbis interim@チューリッヒ レポート
httpbis interim@チューリッヒ レポート
 
第43回HTML5とか勉強会 SPDY/QUICデモ
第43回HTML5とか勉強会 SPDY/QUICデモ第43回HTML5とか勉強会 SPDY/QUICデモ
第43回HTML5とか勉強会 SPDY/QUICデモ
 
HTTP/2.0がもたらす Webサービスの進化(後半)
HTTP/2.0がもたらすWebサービスの進化(後半)HTTP/2.0がもたらすWebサービスの進化(後半)
HTTP/2.0がもたらす Webサービスの進化(後半)
 
HTTP/2.0 HPAC-03 エンコーディング手法 by tatsuhiro_t
HTTP/2.0 HPAC-03 エンコーディング手法 by tatsuhiro_tHTTP/2.0 HPAC-03 エンコーディング手法 by tatsuhiro_t
HTTP/2.0 HPAC-03 エンコーディング手法 by tatsuhiro_t
 
httpbis interim@シアトル レポート (第2回HTTP/2.0接続試験)
httpbis interim@シアトル レポート(第2回HTTP/2.0接続試験)httpbis interim@シアトル レポート(第2回HTTP/2.0接続試験)
httpbis interim@シアトル レポート (第2回HTTP/2.0接続試験)
 
Node の HTTP/2.0 モジュール iij-http2 の実装苦労話
Node の HTTP/2.0 モジュール iij-http2 の実装苦労話Node の HTTP/2.0 モジュール iij-http2 の実装苦労話
Node の HTTP/2.0 モジュール iij-http2 の実装苦労話
 
httpbis interim とhttp2.0相互接続試験の話
httpbis interim とhttp2.0相互接続試験の話httpbis interim とhttp2.0相互接続試験の話
httpbis interim とhttp2.0相互接続試験の話
 
Stream2の基本
Stream2の基本Stream2の基本
Stream2の基本
 
Node.js で SPDYのベンチマーク体験サイトを作りました
Node.js で SPDYのベンチマーク体験サイトを作りましたNode.js で SPDYのベンチマーク体験サイトを作りました
Node.js で SPDYのベンチマーク体験サイトを作りました
 
SPDYの話
SPDYの話SPDYの話
SPDYの話
 
SPDYの中身を見てみよう
SPDYの中身を見てみようSPDYの中身を見てみよう
SPDYの中身を見てみよう
 
node-gypを使ったネイティブモジュールの作成
node-gypを使ったネイティブモジュールの作成node-gypを使ったネイティブモジュールの作成
node-gypを使ったネイティブモジュールの作成
 

そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する

  • 1. そうだったのか! よくわかる process.nextTick() Node.jsのイベントループを理解する IIJ 大津 繁樹 (@jovi0608) 2012年6月28日 東京Node学園6時限目
  • 2.
  • 3. Nodeの歩み(参考) 2007/10 libev公開 2010/08 nodejs_jp開始 2008/05 libeio公開 2010/09 no.de開始 2009/09 Google V8公開 2010/11 Joyent管轄へ 2009/02 ry Node開発開始 2011/02 node-v0.4.0リリース 2009/05 node-v0.0.1リリース 2011/03 東京Node学園#1 2009/06 nodejs ML開始 2011/10 東京Node学園祭 2009/10 npm公開 2011/11 node-v0.6.0リリース 2009/11 JSConf EU ry発表 2011/12 Azureサポート 2010/04 Herokuサポート 2012/01 isaacs管理へ 2010/08 node-v0.2.0リリース 2012/06 node-v0.8.0リリース
  • 4. 今日の話 • Nodeのイベントループとは • process.nextTickとは • node-devでの大論争 • 今後どうなる? • process.nextTickの正しい使 い方 おそらく世界初?の Node-v0.8ベースでイベント ループを解説 (libuvの大幅な変更に追随) (注: 説明はLinuxが対象です。)
  • 5. Nodeのイベントループとは、 • Node の心臓 イベントループが終了したら Node は死にます。
  • 6. Nodeのイベントループの正体 Node が起動する時に uv_run() が呼 ばれます。(src/node.cc:2910) https://github.com/joyent/node/blob/v0.8.0-release/deps/uv/src/unix/core.c#L265
  • 7. イベントループが回り続けるには アクティブな handle/req がなけれ ば イベントループが終了 https://github.com/joyent/node/blob/v0.8.0-release/deps/uv/src/unix/core.c#L252-261
  • 8. handle と req の違い • handle – I/O が発生してない時でもイベントループを 維持 – (例) server.listen() • req – I/Oが発生している時だけイベントループを 維持 – (例) http.get()
  • 9. handle と req の種類 handle req ASYNC 非同期ジョブの操作 CONNECT stream接続 CHECK ループの最後の操作 WRITE stream書き込み FS_EVENT ファイルイベント操作 SHUTDOWN stream停止 FS_POLL statの問い合わせ操作 UDP_SEND udp 送信 IDLE アイドルの時の操作 FS ファイル操作 NAMED_PIPE 名前付きパイプの操作 WORK ワーカスレッド POLL fdイベントの操作 GETADDRINFO アドレス情報取得 PREPARE ループの最初の操作 PROCESS プロセスの操作 TCP TCPの操作 後で見て TIMER タイマー操作 おいて下 TTY UDP TTYPの操作 UDPの操作 さい。
  • 10. 実際のコードでは、(その1) var http = require('http'); アクティブ ハンドル var server = http.createServer(); 0 アクティブハンドルが無いからNode終了
  • 11. 実際のコードでは、(その2) var http = require('http'); var server = http.createServer(); アクティブ server.listen(1234); ハンドル追加 (+1) アクティブハンドルが作成されNode は終了しない。実際は epoll wait (Linux)して
  • 12. 実際のコードでは、(その3) var http = require('http'); var server = http.createServer(); server.listen(1234, function() { アクティブ server.close(); ハンドル削除 (+1-1=0) }); アクティブハンドルがすぐ無効化される のでNode終了
  • 13. イベントループの中身 7つのステップ 1. 時刻更新 2. タイマー実行 3. アイドル実行 4. Prepare実行 5. I/Oイベント実行 (libev) 6. Check実行 7. ハンドル終了
  • 14. Node-v0.8イベントループ概要 終わり 始まり setTimeout() nextTick() 1:時刻更新 7:ハンドル終了 6:run_check 2:run_timers コールバッ イベントループ nextTick() ク 一周(Tick) ユーザ 5:poll 3:run_idle プログラム 4:run_prepare libev+kernel epoll: Linux nextTick() kqueue: BSD event port: Solaris (注: ユーザプログラムは 3: run_idle から始まる
  • 15. イベントループを止めてはいけない! 終わり 始まり setTimeout() nextTick() 1:時刻更新 7:ハンドル終了 6:run_check 2:run_timers こんなコードはダメ! while(1) コールバッ ク while(1) { console.log(‘hoge’); 5:poll } 3:run_idle ずっとここ libev+kernel で止まる! 4:run_prepare epoll: Linux kqueue: BSD nextTick() event port: Solaris (注: ユーザプログラムは 3: run_idle から始まる。
  • 17. 理由1:呼び出し順番 setTimeout(function(){ console.log(‘3:foo’); $ node tick-order.js }, 0); 1:piyo process.nextTick(function() { 2:hoge console.log(‘2:hoge’); 3:foo }); console.log(‘1:piyo’); setTimeout() より process.nextTick() が先に呼ばれる (注: 将来仕様が変わる可能性があります。)
  • 18. 理由1:呼び出し順番 終わり 始まり setTimeout() console.log(‘3:foo’) nextTick() 1:時刻更新 7:ハンドル終了 6:run_check 2:run_timers console.log(‘1:piyo’) コールバッ イベントループ nextTick() ク 一周(Tick) 5:poll 3:run_idle 4:run_prepare console.log(‘2:hoge’) nextTick() (注: ユーザプログラムは 3: run_idle から始まる。)
  • 19. 理由2:入れ子の呼び出し順番 process.nextTick(function() { setTimeout(function(){ console.log(‘4:foo'); $ node tick-order2.js }, 0); 1:piyo process.nextTick(function() { 2:bar console.log(‘3:hoge'); 3:hoge }); 4:foo console.log(‘2:bar'); }); console.log(‘1:piyo’); process.nextTick() のスコープ内でも setTimeout() より process.nextTick() が先に呼ばれる (注: 将来仕様が変わる可能性があります。)
  • 20. 理由2:入れ子の呼び出し順番 終わり 始まり console.log(‘3:hoge’) setTimeout() console.log(‘4:foo’) nextTick() 1:時刻更新 7:ハンドル終了 6:run_check 2:run_timers console.log(‘1:piyo’) コールバッ イベントループ nextTick() ク 一周(Tick) 5:poll 3:run_idle 4:run_prepare console.log(‘2:bar’) nextTick() (注: ユーザプログラムは3: run_idleから始まる。)
  • 21. process.nextTick()の説明(マニュアルより) イベントループの次以降のループでコールバッ クを呼び出します。 これは setTimeout(fn, 0) の 単純なエイリアスではなく、 はるかに効率的で す。 for (var i = 0; i < 1024*1024; i++) { 処理時間 process.nextTick(function (){ Math.sqrt(i); } ); 0.360u 0.072s 0:00.44 97.7% } 約5倍の差 for (var i = 0; i < 1024 * 1024; i++) { setTimeout(function () { Math.sqrt(i) }, 0); 1.700u 0.800s 0:02.51 99.6% } おそらくリンクリストの生成と時刻取得のオーバヘッドによるものだろう(未
  • 22. node-v0.9に向けて isaacs からの提案 • process.nextTick()でイベントハンドラを追加するのはよくやること だけど 次のイベントループでハンドラが登録されるまでの間にイベントが 発生したりするとI/Oの取りこぼしが起きてしまう。 • 次のイベントが発生する前に確実にハンドラを登録をするために、 V8でJSを実行した直後に process.nextTick() に登録された関数を全部 実行するようにしたい。 • 再帰処理とかの展開もそこで行うので次のようなコードでは setTimeout() は起動しなくなるよ。 setTimeout(function() { console.log('timeout'); }, 1000); process.nextTick(function f() { process.nextTick(f); });
  • 23. node-devでの大論争 推進派 擁護派 • 今までの動作がそもそもおか • 別のAPIにすればいいじゃない しかった。正しい動作に変え か るだけ • 実際にコード変更するのがど • CPU処理の分散のために再帰を んなに大変か 使うのは悪いこと、child • どうせ今さら何言っても聞き process を使え 入れてくれないだろう • idle用リスナの用途に再帰を使 うのはわからんでもないが、 setTimeoutを使え • API名を変えるのはもう遅い • 実際にI/Oの取りこぼしでバグ が出ている。この変更でそれ を直すのが優先する
  • 24. 今後どうなるのか(想像) 終わり 始まり setTimeout() 1:時刻更新 7:ハンドル終了 nextTick() nextTick() 2:run_timers 全展開 全展開 6:run_check コールバッ イベントループ ク 一周(Tick) 5:poll 3:run_idle 4:run_prepare libev+kernel epoll: Linux kqueue: BSD event port: Solaris 再帰は一定回数繰り返したら遅延させるかも
  • 25. process.nextTickの正しい使い方 var events = require('events'); var util = require('util'); 非同期イ function Hoge() { ベントの var self = this; 生成 process.nextTick(function() { self.emit('foo'); }); } util.inherits(Hoge, events.EventEmitter); var hoge = new Hoge(); hoge.on('foo', function() { console.log('foo event emitted'); });
  • 26. process.nextTickの正しい使い方 var events = require('events'); var util = require('util'); function Hoge(cb) { 非同期コール if(cb) { バックの呼び出 process.nextTick(function() { cb(); し }); } } util.inherits(Hoge, events.EventEmitter); Hoge.prototype.setfoo = function(arg) { this.foo = arg; }; var hoge = new Hoge(function() { hoge.setfoo('bar'); console.log(hoge.foo); });
  • 27. process.nextTickの再帰を避ける var cluster = require('cluster'); if (cluster.isMaster) { CPU消費処理は var worker = cluster.fork(); 子プロセスで worker.on('message', function(msg) { console.log(msg); }); } else { //子プロセス while(1) { process.send(‘hoge’); } }
  • 28. まとめ • Node のイベントループの仕組みを良く理解 した上でイベントループを止めないことを意 識してコードを書きましょう。 • process.nextTick() は、 – 非同期イベントの発生 – 非同期コールバックの実行 の用途で使いましょう。 • CPUを消費する処理には、child process を利 用しましょう。 • node-v0.9 では process.nextTick()の動作仕様 が変わる予定です。