52

次のテストコードがあります。316934 回または 361992 回ループした後、常に「タスクがキャンセルされました」というエラーが表示されます。

私が間違っていなければ、タスクがキャンセルされた理由として 2 つの可能性があります。

タスクをキューに入れる際の制限に関するドキュメントが見つかりませんでした。そして、500K 以上のタスクを作成してみて、タイムアウトはありませんでした。理由「b」が正しくない可能性があると思います。

Q1. 私が逃した他の理由はありますか?

Q2. HttpClient のタイムアウトが原因である場合、「TaskCancellation」例外の代わりに正確な例外メッセージを取得するにはどうすればよいですか。

Q3. それを修正する最良の方法は何ですか?スロットルを導入する必要がありますか?

ありがとう!

var _httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "text/html,application/xhtml+xml,application/xml");
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Encoding", "gzip, deflate");
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0");
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Charset", "ISO-8859-1");

int[] intArray = Enumerable.Range(0, 600000).ToArray();

var results = intArray                
    .Select(async t => {

        using (HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, "http://www.google.com")) {
            log.Info(t);

            try {

                var response = await _httpClient.SendAsync(requestMessage);
                var responseContent = await response.Content.ReadAsStringAsync();

                return responseContent;
            }
            catch (Exception ex) {
                log.ErrorException(string.Format("SoeHtike {0}", Task.CurrentId), ex);
            }
            return null;
        }
    });

Task.WaitAll(results.ToArray());

Console.ReadLine();

問題を再現する手順は次のとおりです。

  1. VS 2012 でコンソール プロジェクトを作成します。

  2. 私のコードをコピーしてメインに貼り付けてください。

  3. この行にブレークポイントを置きます " log.ErrorException(string.Format("SoeHtike {0}", Task.CurrentId), ex);"

プログラムをデバッグ モードで実行します。数分待ちます。(おそらく 5 分?) コードをテストしたところ、3 分後に例外が発生しました。フィドラーをお持ちの場合は、リクエストを監視して、プログラムがまだ実行されているかどうかを確認できます。

問題を再現できない場合は、遠慮なくお知らせください。

4

4 に答える 4

64

デフォルトHttpClient.Timeout値は 100 秒 (00:01:40) です。ブロックでタイムスタンプcatchを実行すると、タスクがまさにその時点でキャンセルされ始めることに気付くでしょう。どうやら、1 秒間に実行できる HTTP リクエストの数には制限があり、他のリクエストはキューに入れられます。タイムアウト時にキューに入れられたリクエストがキャンセルされます。60 万のタスクのうち、私が個人的に成功したのは 2500 だけで、他のタスクはキャンセルされました。

また、600000 個のタスク全体を実行できる可能性は低いと思います。多くのネットワーク ドライバーは、短時間だけ大量の要求を通過させ、しばらくするとその数を非常に低い値に減らします。私のネットワーク カードでは、36 秒以内に 921 件のリクエストしか送信できず、その速度は 1 秒あたり 1 件のリクエストにまで落ちました。その速度では、すべてのタスクを完了するのに 1 週​​間かかります。

この制限を回避できる場合は、アプリがメモリを大量に消費するため、64 ビット プラットフォーム用のコードをビルドしてください。

于 2013-10-16T15:00:16.290 に答える
35

使用している HttpClient のインスタンスを破棄しないでください。奇妙ですが、この問題は修正されました。

于 2014-09-15T23:00:12.920 に答える
1

共有したかったのですが、サーバーの負荷テストに同様のコードがありましたが、リクエストがタイムアウトする可能性が高い. http リクエストのタイムアウトを最大に設定し、それによって何かが変わるかどうかを確認できます。さまざまなスレッドを作成して、サーバーにアクセスしてみました。また、ヒット数を増やしましたが、最終的にはすべてタイムアウトになります。また、別のスレッドでヒットしたときにタイムアウトを設定することはできません。

于 2013-10-20T05:57:32.110 に答える
0

私は最近これに出くわしました。結局のところ、Web アプリケーションをデバッグ モードで起動すると、起動 URL は https を使用していました。

ただし、(構成ファイル内の) WebApi エンドポイントの URL は http を使用していました。https を使用するように更新すると、WebApi エンドポイントを呼び出すことができました。

于 2020-04-25T18:00:21.923 に答える