2011-08-17 16 views
6

私はNode.jsのを使用して次のような単純なHTTPサーバを持っている:なぜこのjavascriptブロックはNode.jsにありますか?

var http = require('http'); 

var server = http.createServer(function(req, res) { 
    var counter = 0; 

    for(var i = 1; i <= 30; i++) { 
     http.get({ host: "www.google.com" }, function(r) { 
      counter++; 
      res.write("Response " + counter + ": " + r.statusCode + "\n"); 
      if(counter == 30) res.end();                                 
     }); 
    } 
}); 

server.listen(8000); 

私はポート8000​​上で私のローカルホストにカールすると、私は期待した結果の取得を実行します。

Response 1: 200 
Response 2: 200 
Response 3: 200 
... 
Response 30: 200 

しかし、ときに私が最初のプロセスが実行されている間に別の端末からカールしようとすると、コンソールがハングして、最初のプロセスが完全に終了してから同じ出力を受け取るのを待ちます。

これは、ノードがイベントループの次のティックで複数の要求を同期して処理できるコールバックを使用した非同期コードなので、私の理解であった。実際、私はRyan Dahlのビデオを見て、こんにちは世界の例と似たようなことをしていました。私のコードには、サーバーをブロックするものは何ですか?

+0

'http.globalAgent.maxSockets'をより大きい整数(さまざまな回答で指定されているように)に設定できることに加えて、それを' Infinity'に設定して制限を完全に取り除くこともできます。 – skeggse

答えて

8

問題は通話をブロックすることとは関係ありません。これは、一度に特定の数の接続を1つのホストにしか開くことができないという事実と関係しています。開いている接続の最大数に達すると、http.getへの他の非同期呼び出しは、開いている接続の数が再び低下するまで待つ必要があります。これは、他の要求が完了し、コールバックが起動されたときに発生します。新しいリクエストを流すよりも速く新しいリクエストを作成しているので、外見上はブロックされた結果が得られます。

これはテストするために作成したプログラムの修正版です。 (mtomisに示されているように、問題を解決するためのより簡単な方法があります - 詳細は以下を参照してください)。console.logロギングを追加したので、処理されている順番を簡単に伝えることができます。 /以外のリクエストもすべて拒否しますので、favicon.icoリクエストは無視されます。最後に、私は多くのさまざまなウェブサイトへのリクエストを行います。

var http = require('http'); 

// http://mostpopularwebsites.net/1-50/ 
var sites = [ 
    "www.google.com", "www.facebook.com", "www.youtube.com", 
    "www.yahoo.com", "www.blogspot.com", "www.baidu.com", "www.live.com", 
    "www.wikipedia.org", "www.twitter.com", "www.qq.com", "www.msn.com", 
    "www.yahoo.co.jp", "www.sina.com.cn", "www.google.co.in", "www.taobao.com", 
    "www.amazon.com", "www.linkedin.com", "www.google.com.hk", 
    "www.wordpress.com", "www.google.de", "www.bing.com", "www.google.co.uk", 
    "www.yandex.ru", "www.ebay.com", "www.google.co.jp", "www.microsoft.com", 
    "www.google.fr", "www.163.com", "www.google.com.br", 
    "www.googleusercontent.com", "www.flickr.com" 
]; 

var server = http.createServer(function(req, res) { 
    console.log("Got a connection."); 
    if(req.url != "/") { 
    console.log("But returning because the path was not '/'"); 
    res.end(); 
    return; 
    } 

    var counter = 0; 

    for(var i = 1; i <= 30; i++) { 
    http.get({ host: sites[i] }, function(index, host, r) { 
     counter++; 
     console.log("Response " + counter + " from # " + index + " (" + host + ")"); 
     res.write("Response " + counter + " from # " + index + " (" + host + ")\n"); 
     if(counter == 30) res.end(); 
    }.bind(this, i, sites[i])); 
    } 
    console.log("Done with for loop."); 
}); 

server.listen(8000); 

私はこのプログラムを実行し、非常に迅速に(テストは、そうでない場合は良好な出力を得るためにあまりにも速く走っていたとして、私はまた、私のDNSキャッシュをフラッシュ)二つの異なるブラウザでページを訪問しました。ここで出力されます: - 非同期、最高級のI/Oを非ブロック

Got a connection. 
Done with for loop. 
Response 1 from # 8 (www.twitter.com) 
Response 2 from # 1 (www.facebook.com) 
Response 3 from # 12 (www.sina.com.cn) 
Response 4 from # 4 (www.blogspot.com) 
Response 5 from # 13 (www.google.co.in) 
Response 6 from # 19 (www.google.de) 
Response 7 from # 26 (www.google.fr) 
Response 8 from # 28 (www.google.com.br) 
Response 9 from # 17 (www.google.com.hk) 
Response 10 from # 6 (www.live.com) 
Response 11 from # 20 (www.bing.com) 
Response 12 from # 29 (www.googleusercontent.com) 
Got a connection. 
Done with for loop. 
Response 13 from # 10 (www.msn.com) 
Response 14 from # 2 (www.youtube.com) 
Response 15 from # 18 (www.wordpress.com) 
Response 16 from # 16 (www.linkedin.com) 
Response 17 from # 7 (www.wikipedia.org) 
Response 18 from # 3 (www.yahoo.com) 
Response 19 from # 15 (www.amazon.com) 
Response 1 from # 6 (www.live.com) 
Response 2 from # 1 (www.facebook.com) 
Response 3 from # 8 (www.twitter.com) 
Response 4 from # 4 (www.blogspot.com) 
Response 20 from # 11 (www.yahoo.co.jp) 
Response 21 from # 9 (www.qq.com) 
Response 5 from # 2 (www.youtube.com) 
Response 6 from # 13 (www.google.co.in) 
Response 7 from # 10 (www.msn.com) 
Response 8 from # 24 (www.google.co.jp) 
Response 9 from # 17 (www.google.com.hk) 
Response 10 from # 18 (www.wordpress.com) 
Response 11 from # 16 (www.linkedin.com) 
Response 12 from # 3 (www.yahoo.com) 
Response 13 from # 12 (www.sina.com.cn) 
Response 14 from # 11 (www.yahoo.co.jp) 
Response 15 from # 7 (www.wikipedia.org) 
Response 16 from # 15 (www.amazon.com) 
Response 17 from # 9 (www.qq.com) 
Response 22 from # 5 (www.baidu.com) 
Response 23 from # 27 (www.163.com) 
Response 24 from # 14 (www.taobao.com) 
Response 18 from # 5 (www.baidu.com) 
Response 19 from # 14 (www.taobao.com) 
Response 25 from # 24 (www.google.co.jp) 
Response 26 from # 30 (www.flickr.com) 
Response 20 from # 29 (www.googleusercontent.com) 
Response 21 from # 22 (www.yandex.ru) 
Response 27 from # 23 (www.ebay.com) 
Response 22 from # 19 (www.google.de) 
Response 23 from # 21 (www.google.co.uk) 
Response 24 from # 28 (www.google.com.br) 
Response 25 from # 25 (www.microsoft.com) 
Response 26 from # 20 (www.bing.com) 
Response 27 from # 30 (www.flickr.com) 
Response 28 from # 22 (www.yandex.ru) 
Response 28 from # 27 (www.163.com) 
Response 29 from # 25 (www.microsoft.com) 
Response 29 from # 26 (www.google.fr) 
Response 30 from # 21 (www.google.co.uk) 
Response 30 from # 23 (www.ebay.com) 
Got a connection. 
But returning because the path was not '/' 

あなたが見ることができるように、それはAlt+Tab Enterを打つために連れて行ってくれたの期間以外、コールバックは完全に混在しています。

[編集]

mtomisが述べたように、あなたがホストあたりのオープンできる最大接続数がグローバルhttp.globalAgent.maxSockets経由で設定可能です。これをホストごとに処理できる同時接続の数に設定するだけで、確認した問題は消えます。

+0

「なぜ、http.getへの各呼び出しは、前回の呼び出しが返されるまで、そのコールバックを返してトリガーできない」という理由を参照できますか?私はそれがHTTP GET要求を並列に生成したと仮定しました – Raynos

+0

@Brandon Tilley、代理人とそれらを迂回する方法について詳しく書く必要があります。 – thejh

0

あなたは実際に私が思うような要求を、戻ってくることのできるものにしているわけではありません。あなたは1つのイベントハンドラしか持っておらず、ループを一列に並べて実行しています。

Ryan Dahlがその話をした場所を見つけることができますか?

5

ノード。jsには、1ホストあたりのクライアント接続数に制限があります(ホストごとのデフォルト接続数は5です)。http://nodejs.org/docs/v0.5.4/api/http.html#agent.maxSockets

最初のプロセスが終了するまで2番目のカールプロセスがハングアップする理由は、そのうち同時に処理することができるので、第1の処理が完了するまで第2の処理の次の30の要求を処理することはできない。 の例では、http.globalAgent.maxSockets = 60;と設定すると、コールは同時に処理されます。

+0

+1、どういうわけか 'http.globalAgent'のドキュメンテーションをスキップしました。 –

関連する問題