6

Node.jsを使用した次の単純なhttpサーバーがあります。

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

しかし、最初のプロセスの実行中に別の端末からカールインしようとすると、コンソールがハングし、最初のプロセスが完全に終了するのを待ってから、同じ出力の受信を開始します。

私の理解では、これはコールバックを使用する非同期コードであるため、ノードはイベントループの次のティックで複数のリクエストを処理することで同期して複数のリクエストを処理できます。実際、私はRyanDahlがHelloWorldの例と似たようなことをしているビデオを見ました。サーバーをブロックしているコードには何が含まれていますか?

4

3 に答える 3

8

あなたの問題は、通話のブロックとは何の関係もありません。これは、単一のホストに対して一度に特定の数の接続しか開くことができないという事実と関係があります。開いている接続の最大数に達すると、他の非同期呼び出しは、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);

私はこのプログラムを実行し、2つの異なるブラウザーで非常にすばやくページにアクセスしました(テストの実行が速すぎて他の方法では良好な出力が得られなかったため、DNSキャッシュもフラッシュしました)。出力は次のとおりです。

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、コールバックは完全に混ざり合っています。非同期のノンブロッキングI/Oが最高の状態です。

[編集]

mtomisが述べたように、ホストごとに開くことができる最大接続数は、グローバルを介して構成できますhttp.globalAgent.maxSockets。これをホストごとに処理できる同時接続の数に設定するだけで、観察された問題は解消されます。

于 2011-08-17T05:32:14.033 に答える
5

ここに記載されているように、Node.jsにはホストごとのクライアント接続の制限があります(デフォルトではホストごとに5つの接続):http://nodejs.org/docs/v0.5.4/api/http.html#agent.maxSockets

2番目のカールプロセスが最初のプロセスが終了するまでハングする理由は、最初のプロセスが30個のリクエストをキューに入れ、そのうち5個を同時に処理できるため、2番目のプロセスの次の30個のリクエストは、最初のプロセスが完了するまで処理できないためです。完了。あなたの例では、設定http.globalAgent.maxSockets = 60;すると、通話は同時に処理されます。

于 2011-08-17T08:26:03.690 に答える
0

さて、あなたは実際に私が思う要求を、呼び戻すことができる何かに生み出しているのではありません。イベントハンドラーは1つだけで、ループを連続して実行しています。

ライアン・ダールがその話をした場所を見つけることができますか?

于 2011-08-17T03:41:48.417 に答える