2017-04-13 13 views
0

HttpClientの静的なインスタンスを1つ使用するとコードがハングアップし、エラーが発生して数分後に終了することがわかりました。 。静的なhttpclientを複数回呼び出すとコンソールアプリケーションがハングアップする

static HttpClient _client = new HttpClient(); 
    static void Main(string[] args) 
    { 
     try 
     { 
      var t1 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"); 
      t1.Wait(); 
      Console.WriteLine("complete"); 
      var t2 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"); 
      t2.Wait(); 
      Console.WriteLine("complete"); 
      var t3 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"); 
      t3.Wait(); 
      Console.WriteLine("complete"); 
      var t4 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"); 
      t4.Wait(); 
      Console.WriteLine("complete"); 
      Console.ReadKey(); 

     } 
     catch (System.Exception ex) 
     { 

     } 

    } 

次のコードに切り替えて、HttpClientのインスタンスを個別に作成すると、問題はなくなります。

static void Main(string[] args) 
    { 
     try 
     { 
      HttpClient client1 = new HttpClient(); 
      var t1 = client1.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"); 
      t1.Wait(); 
      Console.WriteLine("complete"); 
      HttpClient client2 = new HttpClient(); 
      var t2 = client2.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"); 
      t2.Wait(); 
      Console.WriteLine("complete"); 
      HttpClient client3 = new HttpClient(); 
      var t3 = client3.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"); 
      t3.Wait(); 
      Console.WriteLine("complete"); 
      HttpClient client4 = new HttpClient(); 
      var t4 = client4.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"); 
      t4.Wait(); 
      Console.WriteLine("complete"); 
      Console.ReadKey(); 
     } 
     catch (System.Exception ex) 
     { 

     } 

    } 

私はなぜこれが起こっている最初に知っていただきたいと思い、私は(ちょうど好奇心から、不要)のコードの最初のブロックを持っているよう安全に静的HttpClientを複数回使用する方法がある場合

答えて

1

問題は「GetStreamAsync」メソッドを使用することです。 1つのインスタンスでこのメソッドを複数呼び出すと、 "_client"は同じストリームを開き、このストリームを "t1"、 "t2" ...にコピーします。このオープンストリームでデッドロックを作成します。 "_client"が "t2"のストリームを開くなどの前に、 "GetStringAsync"を使用するか、ストリーム "t1"を閉じる必要があります。あなたがこれを行うことができますどのように、コードを示し、以下:

class Program 
{ 
    private static HttpClient _client = new HttpClient(); 

    static void Main(string[] args) 
    { 
     try 
     { 
      using (var t1 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt")) 
      { 
       t1.Wait(); 
       Console.WriteLine("complete"); 
      } 

      using (var t2 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt")) 
      { 
       t2.Wait(); 
       Console.WriteLine("complete"); 
      } 

      using (var t3 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt")) 
      { 
       t3.Wait(); 
       Console.WriteLine("complete"); 
      } 

      using (var t4 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt")) 
      { 
       t4.Wait(); 
       Console.WriteLine("complete"); 
      } 

      Console.ReadKey(); 

     } 
     catch (System.Exception ex) 
     { 

     } 
    } 

私はプログラムの開発は、「T1」の使用してブロックを残す場合は、自動的に「T1」のDisposeメソッドを呼び出すこと、使用して簡単なを追加しました。

さらに、非同期コードで正常に動作するには、 "await"を使用することをお勧めします。あなたのコードで "await"を使うことができないという問題は、 "Main"メソッドを非同期メソッドにすることができないということです。 「メイン」の方法が行われているので、あなたは、「メイン」方式で「Console.ReadKey」メソッドを呼び出す必要があり

class Program 
{ 
    private static HttpClient _client = new HttpClient(); 

    static void Main(string[] args) 
    { 

     GetStreamsAsync(); 
     Console.ReadKey(); 
    } 

    static async void GetStreamsAsync() 
    { 
     try 
     { 
      using (var t1 = await _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt")) 
      { 
       Console.WriteLine("complete"); 
      } 

      using (var t2 = await _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt")) 
      { 
       Console.WriteLine("complete"); 
      } 

      using (var t3 = await _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt")) 
      { 
       Console.WriteLine("complete"); 
      } 

      using (var t4 = await _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt")) 
      { 
       Console.WriteLine("complete"); 
      } 
     } 
     catch (System.Exception ex) 
     { 

     } 
    } 
} 

:しかし、あなたは、次のような新しい非同期無効メソッドを作成し、これを扱うことができます新しい "async void GetSteamsAsync"メソッドの前に追加します。

UPDATE(コメントのためにStuartに感謝): 他のアプリケーションモデルを使用する場合は、「ConfigureAwait」も使用することをお勧めします。 SynchronizationContextにはキャプチャして続行する必要がないため、コンソールアプリケーションで "ConfigureAwait"を使用するのは意味がありません。

+1

ニース。 'ConfigureAwait(false)'のアドバイスはコンソールアプリケーションでは冗長です。キャプチャして続行するSynchronizationContextがないためです。他のアプリモデルでは、しかし、それは不可欠なアドバイス、または図書館の良い練習になります。 – Stuart

+1

あなたは正しいです!改善していただきありがとうございます。 –

+0

最初のバリエーションは私が元々持っていたのと同じ問題に遭遇し、最初と2番目のタスクが完了してから1〜2分後にハングし、例外がスローされます。 2番目のバリエーションは完璧に機能します。私は最初のほうが 'HttpClient _client = new HttpClient())と似ていると思います。 { var t1 = _client.GetStreamAsync(" http://www.w3.org/TR/PNG/iso_8859-1.txt " ); t1.Wait(); Console.WriteLine( "complete"); } ' – erotavlas

関連する問題