2013-06-16 32 views
18

ノードはノンブロッキングですが、デフォルト動作のhttp.listen(8000)は、すべてのHTTPリクエストが1つずつ処理されることを意味しています。私はこれに驚いてはいけないはずです(ポートの仕組みです)が、複数の並列HTTP要求を処理できるようにコードを書く方法を真剣に考えています。Node.jsでの複数の並列HTTPリクエストの処理

サーバーを作成してポート80を稼働させず、長時間実行してもリクエストキューが長くならないようにするにはどうすればよいですか?

問題を説明するには、以下のコードを実行して、2つのブラウザタブに同時にロードしてみてください。

var http = require('http'); 
http.createServer(function (req, res) { 
    res.setHeader('Content-Type', 'text/html; charset=utf-8'); 
    res.write("<p>" + new Date().toString() + ": starting response"); 
    setTimeout(function() { 
     res.write("<p>" + new Date().toString() + ": completing response and closing connection</p>"); 
     res.end(); 
    }, 4000); 
}).listen(8080); 
+1

http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop/ – Paul

答えて

14

あなたはノードの仕組みを誤解しています。上記のコードは、数百または数千のクライアントからのTCP接続を受け入れ、HTTP要求を読み取り、そこに焼いた4000 msのタイムアウトを待ってから応答を送信することができます。各クライアントは約4000 +少数のミリ秒で応答を得ます。そのsetTimeout中(および任意の入出力操作中)ノードは処理を続行できます。これには、追加のTCP接続を受け入れることが含まれます。私はあなたのコードをテストし、ブラウザはそれぞれ4秒で応答を得る。 2番目のものは、それが動作すると思われる方法であれば、8秒かかるとは限りません。

  1. 54 58から
  2. 54から58
  3. 〜59:私はキーボードでできるとタイムスタンプの秒がそうであるように

    は、私はすぐに4つのタブでcurl -s localhost:8080を走りました56〜00

ここには問題はありませんが、どのように考えられるかはわかりますが、問題はありません。あなたの投稿が示唆されたようにうまくいけば、ノードは完全に壊れてしまいます。

はここで確認するための別の方法です:ジョブはsetTimeoutメソッド呼び出しのコールバック関数の中で行われるため、

for i in 1 2 3 4 5 6 7 8 9 10; do curl -s localhost:8080 &;done                                          
+5

あなたは正しいですか?それはそれをやっているクロムです。少なくとも私にとっては、最初のリクエストが返されるまで、2番目のリクエストは発行されません。 – Andrew

+0

クロムでさえ、通常、原点ごとに最大6つの同時接続が可能です。 –

+1

私は知っています。だから、私は驚いて、それがノードだと思ったのです。 – Andrew

3

あなたのコードでは、複数の接続を受け入れることができます。

しかし、あなたはsetTimeoutの代わりに重い仕事をしたら、それはnode.jsが他の複数の接続を受け入れないことです! SetTimeoutは誤ってプロセスを解放し、node.jsが他のジョブを受け入れ、コードが他の「スレッド」で実行されるようにします。

これを実装する正しい方法がわかりません。しかし、これはどのように動作するようです。

0

私は通常行うように一緒に処理された50のsetTimeoutの秒、すべてのタイムアウトを除いて、この要求は、その多くの処理時間がかかることはありませんので

app.get('/', function(req, res) { 
    console.log('time', MOMENT()); 
    setTimeout(function() { 
    console.log(data, '   ', MOMENT()); 
    res.send(data); 
    data = 'changing'; 
    }, 50000); 
    var data = 'change first'; 
    console.log(data); 
}); 

要求処理をテストするには、次のコードを使用していました。

この後
time moment("2017-05-22T16:47:28.893") 
change first 
time moment("2017-05-22T16:47:30.981") 
change first 
time moment("2017-05-22T16:47:33.463") 
change first 
change first   moment("2017-05-22T16:48:18.923") 
change first   moment("2017-05-22T16:48:20.988") 
change first   moment("2017-05-22T16:48:23.466") 

together-

応答3の要求は、私は私の要求が同期ファイルや時間がかかり、他のいくつかのことを処理するために多くの時間を要し、すなわち、どのような場合には...第二段階に移りました。

app.get('/second', function(req, res) { 
    console.log(data); 
    if(req.headers.data === '9') { 
     res.status(200); 
     res.send('response from api'); 
    } else { 
     console.log(MOMENT()); 
     for(i = 0; i<9999999999; i++){} 
     console.log('Second MOMENT', MOMENT()); 
     res.status(400); 
     res.send('wrong data'); 
    } 

    var data = 'second test'; 
}); 

私の最初のリクエストがまだ処理中だったので、2番目のリクエストはNodeによって受け入れられませんでした。したがって、私はこのように、すべての非同期機能のために2要求 -

undefined 
moment("2017-05-22T17:43:59.159") 
Second MOMENT moment("2017-05-22T17:44:40.609") 
undefined 
moment("2017-05-22T17:44:40.614") 
Second MOMENT moment("2017-05-22T17:45:24.643") 

の応答次しまった前の要求が非同期のような働きを完了する前に他のリクエスト(FS、mysqlの、または呼び出しAPI)を受け入れないノードとノードに仮想スレッドをtheresの、しかしそれはそれを単一スレッドとして自己保持し、以前のスレッドがすべて完了するまで他の要求を処理しません。

1

ブラウザは同じ要求をブロックします。異なるブラウザから呼び出すと、これは並行して動作します。

関連する問題