都内で働くSEの技術的なひとりごと / Technical soliloquy of System Engineer working in Tokyo

都内でサラリーマンやってます。SQL Server を中心とした (2023年からは Azure も。) マイクロソフト系(たまに、OSS系などマイクロソフト以外の技術も...)の技術的なことについて書いています。日々の仕事の中で、気になったことを技術要素関係なく気まぐれに選んでいるので記事内容は開発言語、インフラ等ばらばらです。なお、当ブログで発信、発言は私個人のものであり、所属する組織、企業、団体等とは何のかかわりもございません。ブログの内容もきちんと検証して使用してください。英語の勉強のため、英語の

HttpClient って using 使うと不具合が発生するようなので気になって記事かいてみた

 今日は出張で千葉某所まで移動していたんですが、その途中総武本線が大雨のため運転見合わせとなってしまいました...車内の床もご覧の通り....
f:id:koogucc11:20160913140212j:plain

 というわけでその待ち時間を使い、ある記事を見てちょっと気になったことを記事にしてみます。
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 を使用しているソースコードは無数にあるかと思うんですが、どうなっているでしょう?!やっちゃってる人いっぱいいそう。今日の移動は本当に疲れました。仕事する前に、ちょっと休憩....
f:id:koogucc11:20160913145528j:plain

久しぶりになめろう食べたいなぁ。千葉某所のなめろうは新鮮で非常に美味です(^^♪

鰹のなめろう

鰹のなめろう