我试图了解 C# 中的 async/await 和 Windows 中的 I/O 完成端口的复杂性,并编写代码来验证我的假设。
据我了解,调用WebClient.DownloadStringTaskAsync(...)
将使当前线程注册一个带有I/O完成端口的I/O操作(这可能有点模糊,我还不了解细节),它将创建一个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);
}
}
如您所见,我正在使用 aWebClient
为网页创建 30 个请求(我知道这很慢,需要 15 秒才能响应)。运行此代码,我观察到以下行为: 15 秒后,前 10 个请求完成。再过 15 秒,另外 10 个请求完成,再过 15 秒,其余请求完成。因此,似乎一次只有 10 个未完成的请求(使用 perfmon 我已经验证被调用的 Web 应用程序有 10 个当前请求)。这是为什么?我期待 30 个并发请求,因为我已经按照上面的代码设置了线程池的最大线程数。
这个 SO 问题让我相信这ServicePointManager
可能与它有关,但由于DefaultConnectionLimit
只有 2 我想没有联系。
我意识到这是对一个相当简单的问题的冗长描述。我希望它能让某人更容易准确地指出我的假设在哪里是错误的。
我在 Windows 7、64 位机器上运行它。