私は新しいタスク ライブラリを実験/学習しており、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 はその時点を「記憶」し、ダウンロードを OS レベルに引き渡してスキップし (2 console.write)、すぐにメインに戻り、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 つの間に大きな違いはありません。また、2 つの URL から同時に大きなファイルをダウンロードしようとすると (20 インスタンス)、同様のネットワーク使用率 (12.5%) とダウンロード速度 (10-12MByte/秒) が得られます。私はピークに達していると思いますか?