1

ユーザーがメニューオプション(1-5)を入力して機能を実行し、結果を出力するコンソールアプリケーションがあります。C# - 200個のHTTP取得要求を実行して結果を出力する

いくつかのURLに200個のHTTP取得要求を実行し、すべての結果を戻し、いくつかの作業を行い、ユーザーに出力します。

この私の現在のコード:

 Parallel.For(0, 200, i => 
     { 
      String[] words = webApi.getSplittedClassName(); 
      for (int j = 0; j < words.Length; j++) 
      { 
       wordsList.Add(words[j]); 
      } 

     }); 

getSplittedClassName

public string[] getSplittedClassName() 
    { 
     HttpResponseMessage response = null; 
     try 
     { 
      response = httpClient.GetAsync(url).Result; 
     } 
     catch (WebException e) 
     { 
      return null; 
     } 
     return parser.breakdownClassName(response); 
    } 

、ユーザがオプション番号を入力するので、プログラムが必要な機能をexecutessし、その後、私は入れては、出力、私は非同期でhttp作業を行うことのポイントがないと思ったので、すべての同期しています。

問題は、要求を行うのに多くの時間がかかっていることです。約30〜40秒です。意味がありますか?

基本的に3つの機能があります.1つの要求を実行し、3つの要求を行い、200の要求を実行します。

200リクエストを実行してすべての結果を待つ最良の方法は何ですか? 1つのリクエストのみを送信するときと同じように同期する必要がありますか?

おかげ

+1

なぜ200のGETリクエストを行いたいのですか?リクエストを1つに結合してサーバー上で処理し、ユーザーに出力したいものだけを返すことはできませんか? – DHP

+0

いいえ私は、運動のその部分を傾けることができません。私は速く、ベストプラクティスで、200の要求を行う必要があります結果と出力を作業します。 –

+0

なぜこれを非同期にしないのですか?同期が必要な理由はありますか? – StriplingWarrior

答えて

2

Parallel.For()は、それはあなたのマシンが持っているどのように多くのCPUコアにチューニングされています並列度を使用しますので、あなたの操作は、主にCPUバウンドであることを前提とする傾向があります。しかし、HTTPリクエストはIOバウンドになる傾向があります。そのため、ほとんどの時間はターゲットマシンが情報を返すのを待っています。

これは、非同期処理を使用する良い機会であることを意味します。このような何かを試してみてください:

public async Task<string[]> getSplittedClassName() 
{ 
    HttpResponseMessage response = await httpClient.GetAsync(url); 
    return parser.breakdownClassName(response); 
} 

と、この:

var classNameTasks = Enumerable.Range(1, 200) 
     .Select(i => webApi.getSplittedClassName()) 
     .ToArray(); 
    wordList.AddRange(
     Task.WhenAll(classNameTasks).Result 
      .SelectMany(g => g)); 

説明:

  1. getSplittedClassName()非同期ようにというよりは、それが同期必要なものを取得して、結果を返す作ります結果が利用可能になるとすぐに完了するTask<>を返します。
  2. 私はすべての例外を食べるコードを削除しました。これは一般的には悪いことです。ここで例外があった場合、本当にやりたいことを考えなければなりません:リクエストをやり直すべきでしょうか?例外をスローするだけですか?このような問題を無視するのは、通常、悪い考えです。
  3. Task.WhenAll()は、与えられたタスクのすべての結果を返すTask<>を返します。これらすべてのタスクが同期するのを待ってから、すべてをwordListにバッチとして追加することができます。これは、すべての項目が単一のスレッドでwordListに追加されるため、スレッドセーフです。元のコードには、同時にwordListに値を追加しようとするスレッドが複数ある可能性があります。

また、これは単なる宿題ですが、現実のシナリオであれば、同じURLに同時に200件のリクエストを行っているという事実は、大きな赤い旗。

+0

あなたの答えに感謝します。それは宿題ですが、すべてのリクエストを完了するのにまだ40-50秒かかります。それは普通ですか?さらに、1リクエストと3リクエストのオプションは同期して行う必要がありますか? –

+0

@OfekAgmon:ターゲットサーバがどのように設定されているかわからないので、それは正常かどうかは分かりません。リクエストが返されるまでにどれくらいの時間がかかりますか?また、ターゲットサーバは同時要求を処理するときに、どの程度のパフォーマンス低下が見られるのでしょうか? 1つまたは3つのリクエストを別々に処理する理由はありません.HTTPリクエストは本質的に非同期操作なので、コードを強制的に動作させるためのパフォーマンスの観点からは魅力的な理由はありません。 – StriplingWarrior

+0

大丈夫、ありがとう。もう少し小さなこと - あなたが投稿した2行のコード(Enumerable.Range)を置く方法は、 "public async Task execFeature"というシグネチャを持っています。私は "await"を使用していないと警告しています。したがって、メソッドは同期して実行されます。それは関連しているのでしょうか?なぜなら私はすべてのメソッドをすべて非同期呼び出しで呼び出していて、何らかのタスクを返しているからです。そして、program.csの最初の呼び出しはfeatureService.startService()です。Wait()。それはそうなのでしょうか?ありがとうございます。 –

関連する問題