SlideShare una empresa de Scribd logo
1 de 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()の動作仕様
  が変わる予定です。

Más contenido relacionado

La actualidad más candente

目grep入門 +解説
目grep入門 +解説目grep入門 +解説
目grep入門 +解説murachue
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 TipsTakaaki Suzuki
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Akihiro Suda
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するYoshifumi Kawai
 
こわくない Git
こわくない Gitこわくない Git
こわくない GitKota Saito
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション土岐 孝平
 
テストコードの DRY と DAMP
テストコードの DRY と DAMPテストコードの DRY と DAMP
テストコードの DRY と DAMPYusuke Kagata
 
Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?Takayuki Shimizukawa
 
オススメの標準・準標準パッケージ20選
オススメの標準・準標準パッケージ20選オススメの標準・準標準パッケージ20選
オススメの標準・準標準パッケージ20選Takuya Ueda
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門大樹 小倉
 
本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話Kumazaki Hiroki
 
初心者向けCTFのWeb分野の強化法
初心者向けCTFのWeb分野の強化法初心者向けCTFのWeb分野の強化法
初心者向けCTFのWeb分野の強化法kazkiti
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪Takuto Wada
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021Hiroshi Tokumaru
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Kohei Tokunaga
 
GoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホンGoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホンAkihiko Horiuchi
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!mosa siru
 
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)NTT DATA Technology & Innovation
 
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)NTT DATA Technology & Innovation
 

La actualidad más candente (20)

目grep入門 +解説
目grep入門 +解説目grep入門 +解説
目grep入門 +解説
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
 
Marp Tutorial
Marp TutorialMarp Tutorial
Marp Tutorial
 
こわくない Git
こわくない Gitこわくない Git
こわくない Git
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
 
テストコードの DRY と DAMP
テストコードの DRY と DAMPテストコードの DRY と DAMP
テストコードの DRY と DAMP
 
Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?
 
オススメの標準・準標準パッケージ20選
オススメの標準・準標準パッケージ20選オススメの標準・準標準パッケージ20選
オススメの標準・準標準パッケージ20選
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門
 
本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話
 
初心者向けCTFのWeb分野の強化法
初心者向けCTFのWeb分野の強化法初心者向けCTFのWeb分野の強化法
初心者向けCTFのWeb分野の強化法
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
 
GoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホンGoによるWebアプリ開発のキホン
GoによるWebアプリ開発のキホン
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
 
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
 
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
今こそ知りたいSpring Batch(Spring Fest 2020講演資料)
 

Similar a そうだったのか! よくわかる 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
 
軽量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
 
Hive undocumented feature
Hive undocumented featureHive undocumented feature
Hive undocumented featuretamtam180
 

Similar a そうだったのか! よくわかる 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 プロセスの制御
 
軽量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も-
 
Hive undocumented feature
Hive undocumented featureHive undocumented feature
Hive undocumented feature
 

Más de 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
 

Más de 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()の動作仕様 が変わる予定です。