私の理解する限り、それは本質的に軽量のスレッドです。
いいえ、それは本当ではありません。特定の状況下では、私は真実である可能性Task
がありますが、それはの1つの使用法にすぎません。スレッドをデリゲートに渡して実行させることで、スレッドを開始できます(通常は非同期、場合によっては同期、デフォルトではスレッドプールを使用)。
スレッドを使用する別の方法は、を使用することTaskCompletionSource
です。これを行うと、タスクは(潜在的に)スレッドを作成したり、スレッドプールを使用したりすることはありません。このモデルの一般的な使用法の1つは、イベントベースのAPIをタスクベースのAPIに変換することです。
それが一般的な例であるという理由だけで、私たちが持っているものが閉じられTask
たときに完了するものが欲しいと仮定しましょう。そのイベントが発生したときに発生するイベントFrom
がすでにあります。FormClosed
public static Task WhenClosed(this Form form)
{
var tcs = new TaskCompletionSource<object>();
form.FormClosing += (_, args) =>
{
tcs.SetResult(null);
};
return tcs.Task;
}
を作成しTaskCompletionSource
、問題のイベントにハンドラーを追加します。そのハンドラーで、タスクの完了を通知し、呼び出し元に戻るためのをTaskCompletionSource
提供します。Task
これTask
により、新しいスレッドが作成されることはなく、スレッドプールなども使用されません。
まったく非同期に見えるこの構成を使用して、タスク/イベントベースのモデルを作成できますが、すべての作業を実行するために単一のスレッド(UIスレッド)のみを使用します。
Task
一般に、関数の実行以外の何かを表すを必要とするときはいつでも、を使用することを検討する必要がありますTaskCompletionSource
。WhenAll
これは、、、などの既存のTPLメソッドのいずれかを使用する場合を除いて、通常、問題にアプローチするための適切な概念的な方法ですWhenAny
。
このように「async/await」パターンを悪用することは避けなければなりませんか?
いいえ、虐待ではないので。Task
これは、構成概念と同様に完全に適切な使用法ですasync/await
。たとえば、上記のヘルパーメソッドを使用して記述できるコードについて考えてみます。
private async void button1_Click(object sender, EventArgs e)
{
Form2 popup = new Form2();
this.Hide();
popup.Show();
await popup.WhenClosed();
this.Show();
}
このコードは、読み取りと同じように機能するようになりました。新しいフォームを作成し、自分自身を非表示にし、ポップアップを表示し、ポップアップが閉じるまで待ってから、もう一度自分自身を表示します。ただし、これはブロック待機ではないため、UIスレッドはブロックされません。また、イベントを気にする必要もありません。ハンドラーの追加、複数のコンテキストの処理。ロジックを動かしたり、そのいずれかを動かしたりします。(それはすべて起こります、それは私たちから隠されているだけです。)