HttpWebRequest.BeginGetResponse blocks your thread synchronously.

HttpWebRequest.BeginGetResponse は、非同期メソッドのくせにスレッドをブロックする。

なんてこった。今まで気がつかなかった。そんなことあるわけないと思っていた。

手元のコードで実験したら、17秒もリターンに掛かっていた。

どうしよう。

 

英語のレファレンスに記載があった。

The BeginGetResponse method requires some synchronous setup tasks to complete (DNS resolution, proxy detection, and TCP socket connection, for example) before this method becomes asynchronous. As a result, this method should never be called on a user interface (UI) thread because it might take some time, typically several seconds. In some environments where the webproxy scripts are not configured properly, this can take 60 seconds or more. The default value for the downloadTime attribute on the <webProxyScipt> config file element is one minute which accounts for most of the potential time delay.

BeginGetResponseは、非同期の処理の前に、DNS名前解決やプロキシ検出、TCPソケット接続などのセットアップタスクを同期的に実行する必要があります。これらの処理には典型的に数秒かかるため、このメソッドはUIスレッドで呼びされるべきではありません。とくに、ウェブプロキシスクリプトが適切に構成されていない環境では、これは60秒やそれ以上の時間が掛かる場合があります。最大の遅延時間を決定するのは構成ファイルの<webProxyScript>要素のdownloadTime属性値であり、これの既定値が60秒です。

自分の環境はこれに該当していたらしい。実際、「インターネットオプション」「接続」「LANの設定」「設定を自動的に検出する」がOFFにしたら、1回目のクエリの応答時間が劇的に早くなった。

 

 

この記事では、当初下記を参考に挙げていたが、前記公式文書の方がより良い。

参考情報は Why does HttpWebRequest GetResponse block for such a long time?

If the server is genuinely taking a long time to return any data (as shown in Fiddler) then that's the cause of it. Uploading an 85MB attachment would take a long time to start with, and then the server has to process it. You can't do a lot about that - other than to use an asynchronous method if you're able to get on with more work before the call returns.

サーバの応答に本当に時間が掛かっているのであれば、この現象が起きます。85MBの添付のアップロードは、サーバが処理を開始するまでに長い時間が必要でしょう。この現象についてあなたができることは多くはありません。せいぜいメソッドから戻る前にやれる処理があるなら、非同期メソッドを使って同時に行うことくらいです。