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




   IIJ 大津 繁樹 (@jovi0608)
        2012年6月28日
     東京Node学園6時限目
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
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 (20)

UnityとROSの連携について
UnityとROSの連携についてUnityとROSの連携について
UnityとROSの連携について
UnityTechnologiesJapan002
 
Discordから バーチャルオフィス「Teamflow」 に乗り換えてみた 雑談を生む工夫
Discordから バーチャルオフィス「Teamflow」 に乗り換えてみた 雑談を生む工夫Discordから バーチャルオフィス「Teamflow」 に乗り換えてみた 雑談を生む工夫
Discordから バーチャルオフィス「Teamflow」 に乗り換えてみた 雑談を生む工夫
Koichiro Matsuoka
 
SAT/SMTソルバの仕組み
SAT/SMTソルバの仕組みSAT/SMTソルバの仕組み
SAT/SMTソルバの仕組み
Masahiro Sakai
 
競プロは社会の役に立たない+ベンチャー企業の話 (NPCA夏合宿OB講演).pdf
競プロは社会の役に立たない+ベンチャー企業の話 (NPCA夏合宿OB講演).pdf競プロは社会の役に立たない+ベンチャー企業の話 (NPCA夏合宿OB講演).pdf
競プロは社会の役に立たない+ベンチャー企業の話 (NPCA夏合宿OB講演).pdf
catupper
 
Marp Tutorial
Marp TutorialMarp Tutorial
Marp Tutorial
Rui Watanabe
 
ServiceとRepository
ServiceとRepositoryServiceとRepository
ServiceとRepository
シオリ ショウノ
 
Cartographer を用いた 3D SLAM
Cartographer を用いた 3D SLAMCartographer を用いた 3D SLAM
Cartographer を用いた 3D SLAM
Yoshitaka HARA
 
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
Y Watanabe
 
Teslaにおけるコンピュータビジョン技術の調査 (2)
Teslaにおけるコンピュータビジョン技術の調査 (2)Teslaにおけるコンピュータビジョン技術の調査 (2)
Teslaにおけるコンピュータビジョン技術の調査 (2)
Kazuyuki Miyazawa
 
GoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホンGoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホン
Akihiko Horiuchi
 
Rust で RTOS を考える
Rust で RTOS を考えるRust で RTOS を考える
Rust で RTOS を考える
ryuz88
 
指数時間アルゴリズム入門
指数時間アルゴリズム入門指数時間アルゴリズム入門
指数時間アルゴリズム入門
Yoichi Iwata
 
プログラムを高速化する話
プログラムを高速化する話プログラムを高速化する話
プログラムを高速化する話
京大 マイコンクラブ
 
日本語テストメソッドについて
日本語テストメソッドについて日本語テストメソッドについて
日本語テストメソッドについて
kumake
 
中3女子でもわかる constexpr
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexpr
Genya Murakami
 
Jetson活用セミナー ROS2自律走行実現に向けて
Jetson活用セミナー ROS2自律走行実現に向けてJetson活用セミナー ROS2自律走行実現に向けて
Jetson活用セミナー ROS2自律走行実現に向けて
Fixstars Corporation
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
Takeshi Yamamuro
 
ワタシはSingletonがキライだ
ワタシはSingletonがキライだワタシはSingletonがキライだ
ワタシはSingletonがキライだ
Tetsuya Kaneuchi
 
「スキルなし・実績なし」 32歳窓際エンジニアがシリコンバレーで働くようになるまで
「スキルなし・実績なし」 32歳窓際エンジニアがシリコンバレーで働くようになるまで「スキルなし・実績なし」 32歳窓際エンジニアがシリコンバレーで働くようになるまで
「スキルなし・実績なし」 32歳窓際エンジニアがシリコンバレーで働くようになるまで
Shuichi Tsutsumi
 
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
「関心の分離」と「疎結合」   ソフトウェアアーキテクチャのひとかけら「関心の分離」と「疎結合」   ソフトウェアアーキテクチャのひとかけら
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
Atsushi Nakamura
 
Discordから バーチャルオフィス「Teamflow」 に乗り換えてみた 雑談を生む工夫
Discordから バーチャルオフィス「Teamflow」 に乗り換えてみた 雑談を生む工夫Discordから バーチャルオフィス「Teamflow」 に乗り換えてみた 雑談を生む工夫
Discordから バーチャルオフィス「Teamflow」 に乗り換えてみた 雑談を生む工夫
Koichiro Matsuoka
 
SAT/SMTソルバの仕組み
SAT/SMTソルバの仕組みSAT/SMTソルバの仕組み
SAT/SMTソルバの仕組み
Masahiro Sakai
 
競プロは社会の役に立たない+ベンチャー企業の話 (NPCA夏合宿OB講演).pdf
競プロは社会の役に立たない+ベンチャー企業の話 (NPCA夏合宿OB講演).pdf競プロは社会の役に立たない+ベンチャー企業の話 (NPCA夏合宿OB講演).pdf
競プロは社会の役に立たない+ベンチャー企業の話 (NPCA夏合宿OB講演).pdf
catupper
 
Cartographer を用いた 3D SLAM
Cartographer を用いた 3D SLAMCartographer を用いた 3D SLAM
Cartographer を用いた 3D SLAM
Yoshitaka HARA
 
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
Y Watanabe
 
Teslaにおけるコンピュータビジョン技術の調査 (2)
Teslaにおけるコンピュータビジョン技術の調査 (2)Teslaにおけるコンピュータビジョン技術の調査 (2)
Teslaにおけるコンピュータビジョン技術の調査 (2)
Kazuyuki Miyazawa
 
GoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホンGoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホン
Akihiko Horiuchi
 
Rust で RTOS を考える
Rust で RTOS を考えるRust で RTOS を考える
Rust で RTOS を考える
ryuz88
 
指数時間アルゴリズム入門
指数時間アルゴリズム入門指数時間アルゴリズム入門
指数時間アルゴリズム入門
Yoichi Iwata
 
日本語テストメソッドについて
日本語テストメソッドについて日本語テストメソッドについて
日本語テストメソッドについて
kumake
 
中3女子でもわかる constexpr
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexpr
Genya Murakami
 
Jetson活用セミナー ROS2自律走行実現に向けて
Jetson活用セミナー ROS2自律走行実現に向けてJetson活用セミナー ROS2自律走行実現に向けて
Jetson活用セミナー ROS2自律走行実現に向けて
Fixstars Corporation
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
Takeshi Yamamuro
 
ワタシはSingletonがキライだ
ワタシはSingletonがキライだワタシはSingletonがキライだ
ワタシはSingletonがキライだ
Tetsuya Kaneuchi
 
「スキルなし・実績なし」 32歳窓際エンジニアがシリコンバレーで働くようになるまで
「スキルなし・実績なし」 32歳窓際エンジニアがシリコンバレーで働くようになるまで「スキルなし・実績なし」 32歳窓際エンジニアがシリコンバレーで働くようになるまで
「スキルなし・実績なし」 32歳窓際エンジニアがシリコンバレーで働くようになるまで
Shuichi Tsutsumi
 
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
「関心の分離」と「疎結合」   ソフトウェアアーキテクチャのひとかけら「関心の分離」と「疎結合」   ソフトウェアアーキテクチャのひとかけら
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
Atsushi Nakamura
 

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

Node.jsでブラウザメッセンジャー
Node.jsでブラウザメッセンジャーNode.jsでブラウザメッセンジャー
Node.jsでブラウザメッセンジャー
Yahoo!デベロッパーネットワーク
 
東京Node学園#3 Domains & Isolates
東京Node学園#3 Domains & Isolates東京Node学園#3 Domains & Isolates
東京Node学園#3 Domains & Isolates
koichik
 
Nodejuku01 ohtsu
Nodejuku01 ohtsuNodejuku01 ohtsu
Nodejuku01 ohtsu
Nanha Park
 
Reactive Programming
Reactive ProgrammingReactive Programming
Reactive Programming
maruyama097
 
Flow.js
Flow.jsFlow.js
Flow.js
uupaa
 
SmartPhone development guide with CoffeeScript + Node + HTML5 Technology, for...
SmartPhone development guide with CoffeeScript + Node + HTML5 Technology, for...SmartPhone development guide with CoffeeScript + Node + HTML5 Technology, for...
SmartPhone development guide with CoffeeScript + Node + HTML5 Technology, for...
Naoya Ito
 
PerlとJavaScriptとAndroidとiOSとのんのんバアとオレ
PerlとJavaScriptとAndroidとiOSとのんのんバアとオレPerlとJavaScriptとAndroidとiOSとのんのんバアとオレ
PerlとJavaScriptとAndroidとiOSとのんのんバアとオレ
Naosuke Yokoe
 
イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化
Gosuke Miyashita
 
Node予備校 vol.1 名古屋
Node予備校 vol.1 名古屋Node予備校 vol.1 名古屋
Node予備校 vol.1 名古屋
Mori Shingo
 
Node.js - JavaScript Thread Programming
Node.js - JavaScript Thread ProgrammingNode.js - JavaScript Thread Programming
Node.js - JavaScript Thread Programming
takesako
 
React+redux+saga 03
React+redux+saga 03React+redux+saga 03
React+redux+saga 03
TIS Inc
 
たのしいNode.js
たのしいNode.jsたのしいNode.js
たのしいNode.js
ishiki-takai
 
Em synchrony について
Em synchrony についてEm synchrony について
Em synchrony について
Tomoya Kawanishi
 
EchoyaGinhanazeSu_inoka.pptx
EchoyaGinhanazeSu_inoka.pptxEchoyaGinhanazeSu_inoka.pptx
EchoyaGinhanazeSu_inoka.pptx
keink
 
Reactive
ReactiveReactive
Reactive
Akihiro Ikezoe
 
オタク×Node.js勉強会
オタク×Node.js勉強会オタク×Node.js勉強会
オタク×Node.js勉強会
虎の穴 開発室
 
Janogia20120921 yoshinotakeshi
Janogia20120921 yoshinotakeshiJanogia20120921 yoshinotakeshi
Janogia20120921 yoshinotakeshi
Keisuke Ishibashi
 
Node.js - sleep sort algorithm
Node.js - sleep sort algorithmNode.js - sleep sort algorithm
Node.js - sleep sort algorithm
takesako
 
東京Node学園#3 Domains & Isolates
東京Node学園#3 Domains & Isolates東京Node学園#3 Domains & Isolates
東京Node学園#3 Domains & Isolates
koichik
 
Nodejuku01 ohtsu
Nodejuku01 ohtsuNodejuku01 ohtsu
Nodejuku01 ohtsu
Nanha Park
 
Reactive Programming
Reactive ProgrammingReactive Programming
Reactive Programming
maruyama097
 
Flow.js
Flow.jsFlow.js
Flow.js
uupaa
 
SmartPhone development guide with CoffeeScript + Node + HTML5 Technology, for...
SmartPhone development guide with CoffeeScript + Node + HTML5 Technology, for...SmartPhone development guide with CoffeeScript + Node + HTML5 Technology, for...
SmartPhone development guide with CoffeeScript + Node + HTML5 Technology, for...
Naoya Ito
 
PerlとJavaScriptとAndroidとiOSとのんのんバアとオレ
PerlとJavaScriptとAndroidとiOSとのんのんバアとオレPerlとJavaScriptとAndroidとiOSとのんのんバアとオレ
PerlとJavaScriptとAndroidとiOSとのんのんバアとオレ
Naosuke Yokoe
 
イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化
Gosuke Miyashita
 
Node予備校 vol.1 名古屋
Node予備校 vol.1 名古屋Node予備校 vol.1 名古屋
Node予備校 vol.1 名古屋
Mori Shingo
 
Node.js - JavaScript Thread Programming
Node.js - JavaScript Thread ProgrammingNode.js - JavaScript Thread Programming
Node.js - JavaScript Thread Programming
takesako
 
React+redux+saga 03
React+redux+saga 03React+redux+saga 03
React+redux+saga 03
TIS Inc
 
たのしいNode.js
たのしいNode.jsたのしいNode.js
たのしいNode.js
ishiki-takai
 
EchoyaGinhanazeSu_inoka.pptx
EchoyaGinhanazeSu_inoka.pptxEchoyaGinhanazeSu_inoka.pptx
EchoyaGinhanazeSu_inoka.pptx
keink
 
Janogia20120921 yoshinotakeshi
Janogia20120921 yoshinotakeshiJanogia20120921 yoshinotakeshi
Janogia20120921 yoshinotakeshi
Keisuke Ishibashi
 
Node.js - sleep sort algorithm
Node.js - sleep sort algorithmNode.js - sleep sort algorithm
Node.js - sleep sort algorithm
takesako
 
Ad

More from shigeki_ohtsu (19)

Node最新トピックス
Node最新トピックスNode最新トピックス
Node最新トピックス
shigeki_ohtsu
 
TLS, HTTP/2演習
TLS, HTTP/2演習TLS, HTTP/2演習
TLS, HTTP/2演習
shigeki_ohtsu
 
HTTP/2, QUIC入門
HTTP/2, QUIC入門HTTP/2, QUIC入門
HTTP/2, QUIC入門
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 QUIC
shigeki_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_t
shigeki_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
 
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 QUIC
shigeki_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_t
shigeki_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
 
Ad

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

  • 1. そうだったのか! よくわかる process.nextTick() Node.jsのイベントループを理解する IIJ 大津 繁樹 (@jovi0608) 2012年6月28日 東京Node学園6時限目
  • 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()の動作仕様 が変わる予定です。