HttpClient って using 使うと不具合が発生するようなので気になって記事かいてみた
今日は出張で千葉某所まで移動していたんですが、その途中総武本線が大雨のため運転見合わせとなってしまいました...車内の床もご覧の通り....
というわけでその待ち時間を使い、ある記事を見てちょっと気になったことを記事にしてみます。
www.infoq.com
aspnetmonsters.com
下記のロジックですが、C# の開発者( VB.NET も ) には至って普通のソースコードに見えるかと思います。using を使ってきちんとオブジェクトのライフタイムもきちんと考慮しているな、と見ることができます。
using System; using System.Net.Http; namespace ConsoleApplication { public class Program { public static void Main(string[] args) { Console.WriteLine("Starting connections"); for(int i = 0; i<10; i++) { using(var client = new HttpClient()) { var result = client.GetAsync("http://aspnetmonsters.com").Result; Console.WriteLine(result.StatusCode); } } Console.WriteLine("Connections done"); } } }
The using statement is a C# nicity for dealing with disposable objects. Once the using block is complete then the disposable object, in this case HttpClient, goes out of scope and is disposed. The dispose method is called and whatever resources are in use are cleaned up. This is a very typical pattern in .NET and we use it for everything from database connections to stream writers. Really any object which has external resources that must be clean up uses the IDisposable interface.
And you can’t be blamed for wanting to wrap it with the using. First of all, it’s considered good practice to do so. In fact, the official docs for using state:
As a rule, when you use an IDisposable object, you should declare and instantiate it in a using statement.
そう、using 使うのがセオリーですよね。しかし、HttpClient に関しては異なるようです。
Huh, that’s weird…the application has exited and yet there are still a bunch of these connections open to the Azure machine which hosts the ASP.NET Monsters website. They are in the TIME_WAIT state which means that the connection has been closed on one side (ours) but we’re still waiting to see if any additional packets come in on it because they might have been delayed on the network somewhere. Here is a diagram of TCP/IP states I stole from
上記のソースでは、HttpClient を使って非同期に 10回リクエストを投げていますが、一つだけコネクションが確立され、それ以外の接続はすべて WAIT 状態となってしまいます。これは問題ですね。
HttpClient はシングルインスタンスにして使用することがセオリーのようです。下記の記事にも同様の記載があります。
performance-optimization/ImproperInstantiation.md at master · mspnp/performance-optimization · GitHub
下記のように修正する必要があります。
using System; using System.Net.Http; namespace ConsoleApplication { public class Program { private static HttpClient Client = new HttpClient(); public static void Main(string[] args) { Console.WriteLine("Starting connections"); for(int i = 0; i<10; i++) { var result = Client.GetAsync("http://aspnetmonsters.com").Result; Console.WriteLine(result.StatusCode); } Console.WriteLine("Connections done"); Console.ReadLine(); } } }
記事にも記載がありましたが、HttpClient を使用しているソースコードは無数にあるかと思うんですが、どうなっているでしょう?!やっちゃってる人いっぱいいそう。今日の移動は本当に疲れました。仕事する前に、ちょっと休憩....
久しぶりになめろう食べたいなぁ。千葉某所のなめろうは新鮮で非常に美味です(^^♪
- 出版社/メーカー: 株式会社紀伊長島
- メディア: その他
- この商品を含むブログを見る