オプション 3 が最適です。
非同期 IO を使用します。
リクエスト処理が複雑で負荷が高い場合を除き、プログラムは時間の 99% を HTTP リクエストの待機に費やすことになります。
これはまさに Async IO が設計された目的です。Windows ネットワーク スタック (または .net フレームワークなど) にすべての待機を心配させ、単一のスレッドを使用してディスパッチし、結果を「取得」します。
残念ながら、.NET フレームワークでは、これが厄介な問題になっています。raw ソケットまたは Win32 API を使用している場合は簡単です。とにかく C#3 を使用した (テスト済みの) 例を次に示します。
using System.Net; // need this somewhere
// need to declare an class so we can cast our state object back out
class RequestState {
public WebRequest Request { get; set; }
}
static void Main( string[] args ) {
// stupid cast neccessary to create the request
HttpWebRequest request = WebRequest.Create( "http://www.stackoverflow.com" ) as HttpWebRequest;
request.BeginGetResponse(
/* callback to be invoked when finished */
(asyncResult) => {
// fetch the request object out of the AsyncState
var state = (RequestState)asyncResult.AsyncState;
var webResponse = state.Request.EndGetResponse( asyncResult ) as HttpWebResponse;
// there we go;
Debug.Assert( webResponse.StatusCode == HttpStatusCode.OK );
Console.WriteLine( "Got Response from server:" + webResponse.Server );
},
/* pass the request through to our callback */
new RequestState { Request = request }
);
// blah
Console.WriteLine( "Waiting for response. Press a key to quit" );
Console.ReadKey();
}
編集:
.NET の場合、'完了コールバック' は実際にはメイン スレッドではなく ThreadPool スレッドで起動されるため、共有リソースをロックする必要がありますが、スレッドを管理する手間を省くことができます。