Task.DelayとThread.Sleepをいつ使用するかに関する適切なルールはありますか?
- 具体的には、一方が他方よりも効果的/効率的であることを提供するための最小値はありますか?
- 最後に、Task.Delayはasync / awaitステートマシンでコンテキスト切り替えを引き起こすため、それを使用するとオーバーヘッドが発生しますか?
Task.DelayとThread.Sleepをいつ使用するかに関する適切なルールはありますか?
回答:
Thread.Sleep
現在のスレッドをブロックする場合に使用します。
Task.Delay
現在のスレッドをブロックせずに論理的な遅延が必要な場合に使用します。
これらの方法では、効率を最優先する必要はありません。それらの実際の主な用途は、I / O操作の再試行タイマーとしての使用であり、ミリ秒ではなく秒単位です。
Thread.Sleep
コンテキストの切り替えを引き起こす現在のスレッドをブロックします。スレッドプールを使用している場合、これにより新しいスレッドが割り当てられる可能性もあります。両方の操作は非常に重いですが、Task.Delay
etc によって提供される協調的なマルチタスクは、そのオーバーヘッドをすべて回避し、スループットを最大化し、キャンセルを許可し、よりクリーンなコードを提供するように設計されています。
onesi: I would use
Thread.Sleep`は、同期メソッド内で待機します。ただし、これを製品コードで行うことはありません。私の経験では、Thread.Sleep
これまでに目にしたことはすべて、適切に修正する必要があるある種の設計上の問題を示しています。
最大の違いTask.Delay
とはThread.Sleep
つまりTask.Delay
非同期で実行することを意図しています。Task.Delay
同期コードで使用しても意味がありません。Thread.Sleep
非同期コードで使用するのは非常に悪い考えです。
通常Task.Delay()
、次のawait
キーワードで呼び出します。
await Task.Delay(5000);
または、遅延の前にいくつかのコードを実行する場合:
var sw = new Stopwatch();
sw.Start();
Task delay = Task.Delay(5000);
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
await delay;
これが何を印刷するかを推測しますか?0.0070048秒実行します。代わりにawait delay
上記を移動すると、Console.WriteLine
実行中と5.0020168秒間印刷されます。
との違いを見てみましょうThread.Sleep
:
class Program
{
static void Main(string[] args)
{
Task delay = asyncTask();
syncCode();
delay.Wait();
Console.ReadLine();
}
static async Task asyncTask()
{
var sw = new Stopwatch();
sw.Start();
Console.WriteLine("async: Starting");
Task delay = Task.Delay(5000);
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
await delay;
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
Console.WriteLine("async: Done");
}
static void syncCode()
{
var sw = new Stopwatch();
sw.Start();
Console.WriteLine("sync: Starting");
Thread.Sleep(5000);
Console.WriteLine("sync: Running for {0} seconds", sw.Elapsed.TotalSeconds);
Console.WriteLine("sync: Done");
}
}
これが何を印刷するかを予測してみてください...
async:開始
async:0.0070048秒実行中
sync:開始
async:5.0119008秒実行中
async:完了
sync:5.0020168秒実行中
sync:完了
また、これはThread.Sleep
はるかに正確であり、msの精度は実際には問題ではありませんが、Task.Delay
15〜30 ミリ秒かかることもあります。両方の関数のオーバーヘッドは、それらが持っているms精度と比較して最小限Stopwatch
です(より正確なものが必要な場合はClassを使用してください)。Thread.Sleep
まだあなたのスレッドを拘束し、Task.Delay
あなたが待っている間、他の仕事をするためにそれを解放します。
Thread.Sleep()
すると、他の場所で使用できるスレッド全体が消費されます。Thread.Sleep()を使用して多くのタスクを実行すると、すべてのスレッドプールスレッドが使い果たされ、パフォーマンスが著しく低下する可能性が高くなります。
async
メソッドの意味で非同期コードの概念が欠けていました。メソッドの使用が推奨されているからです。Thread.Sleep()
スレッドプールスレッドで実行することは基本的には悪い考えであり、一般的に悪い考えではありません。結局のところ、TaskCreationOptions.LongRunning
(がっかりしましたが)Task.Factory.StartNew()
ルートに行くときがあります。
await wait
Tasl.Delay
は、システムタイマーを使用するものです。「システムクロックは一定の速度で「ティック」するため」、システムタイマーのティック速度は約16ミリ秒です。要求する遅延は、システムクロックのティック数に丸められ、最初のクロックまでの時間でオフセットされます。ダニ。上のMSDNドキュメントを参照してくださいTask.Delay
docs.microsoft.com/en-us/dotnet/api/...をし、発言までスクロールします。
現在のスレッドが強制終了され、使用Thread.Sleep
していて実行中の場合、を取得する可能性がありThreadAbortException
ます。ではTask.Delay
、あなたは常にキャンセルトークンを提供し、優雅にそれを殺すことができます。それが私が選択する理由の1つTask.Delay
です。http://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspxを参照してください
この場合、効率が最優先されないことにも同意します。
await Task.Delay(5000)
。タスクを強制終了すると、取得TaskCanceledException
(および抑制)されますが、スレッドはまだ生きています。きちんと!:)
何か追加したいです。実際にTask.Delay
は、タイマーベースの待機メカニズムです。ソースを見るTimer
と、遅延の原因となっているクラスへの参照が見つかります。一方、Thread.Sleep
実際には現在のスレッドをスリープ状態にするため、1つのスレッドをブロックして無駄にしているだけです。非同期プログラミングモデルではTask.Delay()
、なんらかの遅延の後に何か(継続)を発生させたい場合は、常に使用する必要があります。