C# の async/await と Windows の I/O 完了ポートの複雑さを理解しようとしており、途中で自分の仮定を検証するコードを書いています。
私が理解していることから、呼び出すと、現在のスレッドが I/O 完了ポートを使用して I/O 操作に登録されますWebClient.DownloadStringTaskAsync(...)
(これはおそらく少しあいまいです。詳細はまだわかりません)。Task<string>
コードを実行しています。ある時点でawait
、指定されたタスクの に遭遇します。その時点で、現在のメソッドから戻ります (まあ、何らかのスコープから抜けます。このスコープがメソッド以外のものであるかどうかはわかりません。生成されたステート マシンを調べて、その部分を理解する必要があります)。 . I/O 操作が完了すると、スレッドがスレッド プールから取得され、I/O 操作の結果が渡され、前述のスコープの残りが実行されます。
この動作を確認しようとしましたが、何かが正しくないように見える前に、この C# コードまでしか取得できませんでした。
class Program
{
static void Main(string[] args)
{
ThreadPool.SetMaxThreads(30, 30);
Console.WriteLine("Connection limit is {0}", ServicePointManager.DefaultConnectionLimit);
for (int i = 0; i < 30; i++)
{
FetchAsync(i);
}
Console.WriteLine("Done starting requests");
Console.ReadKey();
}
private async static void FetchAsync(int num)
{
WebClient wc = new WebClient();
string result = await wc.DownloadStringTaskAsync("http://localhost/slow/index/15");
Console.WriteLine("Done #{0}", num);
}
}
ご覧のとおりWebClient
、Web ページに対する 30 のリクエストを作成するために を使用しています (これは遅く、応答に 15 秒かかることがわかっています)。このコードを実行すると、次の動作が観察されます。15 秒後、最初の 10 個のリクエストが完了します。さらに 15 秒後に別の 10 の要求が完了し、さらにさらに 15 秒後に残りの要求が完了します。したがって、一度に 10 個の未処理のリクエストしかないように見えます (perfmon を使用して、呼び出されている Web アプリケーションに現在 10 個のリクエストがあることを確認しました)。何故ですか?上記のコードに従ってスレッド プールのスレッドの最大数を設定したため、30 の同時要求が予想されていました。
このSOの質問ServicePointManager
は、それと関係があるかもしれないと私に信じさせましたが、DefaultConnectionLimit
は2つしかないので、関係はないと思います.
これは、かなり単純な質問の非常に長い説明であることに気付きました。誰かが私の仮定が間違っている場所を正確に指摘しやすくなることを願っています.
これを Windows 7、64 ビット マシンで実行しています。