SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

CoffeeScriptによるモダンなWebアプリケーション開発

CoffeeScriptベストプラクティス集
Node.jsアプリケーション編(4)

CoffeeScriptによるモダンなWebアプリケーション開発 第6回

  • X ポスト
  • このエントリーをはてなブックマークに追加

マルチプロセス化

 1つのnodeプロセスはシングルスレッドで動き、CPU1個をフルに使うことができます。そのため、複数のCPUを持つシステムでnodeプロセスを1つだけ稼働させても、システムの性能を最大限発揮することはできません。しかし、nodeプロセスを複数起動すると、1プロセスにつきCPU1個をフルに使うことでシステムの性能を最大限活用できます。標準APIのClusterというモジュールを使うと、プログラムを簡単にマルチプロセス化できます。

 ClusterはAPIの安定度が執筆時点で「1(実験的)」となっており、将来のバージョンでAPIが大幅に変更される可能性があります。

子プロセスを起動してメッセージをやりとりする

 Clusterを使って子プロセスを複数起動させ、親プロセスと子プロセスとの通信機能を利用して、子プロセスを関数実行サーバーのように利用できます。リスト2ではマスタ(親プロセス)がCPUの数だけワーカー(子プロセス)を起動しています。それぞれのワーカーが計算した結果はマスタが受け取ります。この例でワーカーが実行する処理は非常に単純ですが、重い処理を子プロセスで手分けして処理させるとうまくCPU資源を活用することができます。

 cluster.fork()を呼ぶごとにワーカーが1つ作成されます。ワーカーのプロセスはマスタと同じコマンドライン引数で起動されます。ワーカーからcluster.fork()を呼ぶことはできません。

[リスト2]マスタとワーカーでメッセージをやりとりする
cluster = require 'cluster'

# CPUの数を取得し、それをワーカー(子プロセス)の作成数とする
numWorkers = require('os').cpus().length

if cluster.isMaster  # マスタ(親プロセス)の場合だけ実行する処理

  # ワーカーのプロセスが終了した時に呼ばれる
  cluster.on 'death', (worker) ->
    console.log "worker #{worker.pid} が終了した"
      
  for i in [0...numWorkers]
    # ワーカーを作成する
    worker = cluster.fork()
    console.log "worker #{worker.pid}"

    # ワーカーからメッセージが来た時にコールバックが呼ばれる。
    # msgはワーカーから来たオブジェクト。
    worker.on 'message', (msg) ->
      # ここでのthisはメッセージの送信元のworkerオブジェクトを表す。
      # 外側のスコープのworker変数を誤って使わないように注意。

      if msg.cmd is 'ready'  # ワーカーの準備が完了した
        # ワーカーにメッセージを送信
        @send cmd:'add', num1:@pid, num2:100000

      else if msg.cmd is 'reply'  # ワーカーから計算結果が来た
        console.log "result from #{@pid}: #{msg.result}"

        @kill()  # ワーカーのプロセスを終了させる

else  # ワーカーの場合だけ実行する処理

  # マスタからメッセージが来た時に呼ばれる。
  # msgはマスタから来たオブジェクト。
  process.on 'message', (msg) ->
    if msg.cmd is 'add'
      result = msg.num1 + msg.num2
      # マスタに計算結果を送信
      process.send cmd:'reply', result:result

  # 準備が完了したことをマスタに知らせる
  process.send cmd:'ready'

 実行結果は以下のようになります。

実行結果
worker 66024
worker 66025
worker 66026
worker 66027
result from 66026: 166026
worker 66026 が終了した
result from 66024: 166024
worker 66024 が終了した
result from 66027: 166027
worker 66027 が終了した
result from 66025: 166025
worker 66025 が終了した

複数の子プロセスを同じポートで待機させる

 Clusterを使って複数の子プロセスを同一のポート番号で待機させることができます。

[リスト3]1つのTCPポートで複数の子プロセスを待機させる
cluster = require 'cluster'
http = require 'http'

# CPUの数を取得し、それをワーカーの作成数とする
numWorkers = require('os').cpus().length

if cluster.isMaster  # 親プロセスの場合
  for i in [0...numWorkers]
    # 子プロセスを作成する。
    cluster.fork()

else  # 子プロセスの場合
  # TCPの3000番ポートで待ち受ける
  http.createServer (req, res) ->
    res.writeHead 200
    res.end "Hello World by #{process.pid}\n"
  .listen 3000

 このプログラムを起動すると、クライアントがアクセスしてきた時に手の空いているワーカーが処理を引き受けます。

エラー処理

 プログラム内でthrow文により例外がスローされ、どこにもキャッチされなかった場合、プロセスはスタックトレースを出力して終了してしまいます。しかし、uncaughtExceptionイベントにリスナを登録しておくと、そういった例外をキャッチしてプログラムの終了を防ぐことができます(リスト4)。常時起動させるプログラムを作成する場合は、意図せずプログラムが終了してしまうのを防ぐ保険の意味合いで入れておきましょう。

 ただしあくまでも最後の保険なので、uncaughtExceptionに頼って例外処理をすることは避けましょう。例外が発生しそうな箇所にはあらかじめtry/catchを入れておくのがベストです。

[リスト4]どこにもキャッチされなかった例外をキャッチする
process.on 'uncaughtException', (err) ->
  console.log "例外をキャッチ: #{err}"
  console.log "name: #{err.name}"
  console.log "message: #{err.message}"
  console.log "stack: #{err.stack}"

process.nextTick ->
  console.log obj.prop
実行結果
例外をキャッチ: ReferenceError: obj is not defined
name: ReferenceError
message: obj is not defined
stack: ReferenceError: obj is not defined
    at Array.0 (/Users/nao/git/coffeebook/exception/test.coffee:11:24)
    at EventEmitter._tickCallback (node.js:192:40)

 なお、Errorオブジェクトはnamemessagestackというプロパティを持っており、エラーの詳細について個別に取得できます。それぞれのプロパティの内容は次の通りです。

  • name:エラーの名前
  • message:エラーの内容
  • stack:スタックトレース

次のページ
デーモン化

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
CoffeeScriptによるモダンなWebアプリケーション開発連載記事一覧

もっと読む

この記事の著者

飯塚 直(イイヅカ ナオ)

1984年東京都生まれ。 高校時代に趣味でPerlやJavaを使ってプログラミングを始める。 慶応大学湘南藤沢キャンパス卒業後、共同通信社にてニュースサイトの開発などを担当。 その後、面白法人カヤックにてソーシャルゲームの開発などを手がける。 2012年現在、カヤックを退社し個人として活動し...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/6530 2012/05/07 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング