我正在试验/学习新的任务库,并使用 WebClient 和 Task.Run 编写了一个非常简单的 html 下载器。但是,我的网络使用率永远不会超过 5%。我想了解为什么以及如何改进我的代码以达到 100% 的网络使用率/吞吐量(可能不可能,但必须远远超过 5%)。
我也希望能够限制线程的数量,但它似乎并不像我想象的那么容易(即自定义任务调度程序)。有没有办法做这样的事情来设置最大线程数:something.SetMaxThread(2)?
internal static class Program
{
private static void Main()
{
for (var i = 0; i < 1000000; i++)
{
Go(i, Thread.CurrentThread.ManagedThreadId);
}
Console.Read();
}
private static readonly Action<int, int> Go = (counter, threadId) => Task.Run(() =>
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var webClient = new WebClient();
webClient.DownloadString(new Uri("http://stackoverflow.com"));
stopwatch.Stop();
Console.Write("{0} == {1} | ", threadId.ToString("D3"), Thread.CurrentThread.ManagedThreadId.ToString("D3"));
Console.WriteLine("{0}: {1}ms ", counter.ToString("D3"), stopwatch.ElapsedMilliseconds.ToString("D4"));
});
}
这是根据@spender 的异步版本。但是我的理解是 await 将“记住”时间点并将下载移交给操作系统级别并跳过(2 console.write)并立即返回 main 并继续在 for 循环中调度剩余的 Go 方法。我理解正确吗?所以UI上没有阻塞。
private static async void Go(int counter, int threadId)
{
using (var webClient = new WebClient())
{
var stopWatch = new Stopwatch();
stopWatch.Start();
await webClient.DownloadStringTaskAsync(new Uri("http://ftp.iinet.net.au/test500MB.dat"));
stopWatch.Stop();
Console.Write("{0} == {1} | ", threadId.ToString("D3"), Thread.CurrentThread.ManagedThreadId.ToString("D3"));
Console.WriteLine("{0}: {1}ms ", counter.ToString("D3"), stopWatch.ElapsedMilliseconds.ToString("D4"));
}
}
我注意到的是,当我下载大文件时,下载速度/网络使用情况没有太大差异。它们(线程版本和异步版本)都达到了大约 12.5% 的网络使用率和大约 12MByte 下载/秒的峰值。我还尝试运行多个实例(运行多个 .exe),而且两者之间没有太大区别。当我尝试同时从 2 个 URL(20 个实例)下载大文件时,我得到了相似的网络使用率(12.5%)和下载速度(10-12MByte /sec)。我想我达到了顶峰?