36

TaskCompletionSource非同期/スレッドレス作業の目的とその関係を理解し​​ようとしています。私は一般的な考えを持っていると思いますが、私の理解が正しいことを確認したいと思います。

私は最初にタスク並列ライブラリ(TPL)を調べて、独自のスレッドレス/非同期作業(ASP.NETサイトのスケーラビリティを向上させようとしているなど)とTPLの理解を作成する良い方法があるかどうかを調べ始めました。将来的には非常に重要になるようです(async/ await)。それは私をに導きましたTaskCompletionSource

私の理解でTaskCompletionSourceは、クラスの1つに追加しても、コーディングを非同期にするほどの効果はないようです。まだ同期コードを実行している場合は、コードの呼び出しがブロックされます。これはMicrosoftAPIにも当てはまると思います。たとえば、クラスDownloadStringTaskAsync外ではWebClient、最初に実行しているセットアップ/同期コードはすべてブロックされます。実行しているコードは、現在のスレッドのいずれかのスレッドで実行する必要があります。そうでない場合は、新しいスレッドをスピンオフする必要があります。

したがって、MicrosoftからTaskCompletionSource他の呼び出しを呼び出すときに独自のコードで使用するasyncため、クラスのクライアントは、クラスがブロックしないように新しいスレッドを作成する必要がありません。

Microsoftが非同期APIを内部でどのように実行しているかわからない。たとえば、for.Net4.5asyncには新しい方法があります。SqlDataReaderIO完了ポートがあることは知っています。おそらくほとんどのC#開発者が使用しないのは低レベルの抽象化(C ++?)だと思います。IO完了ポートがデータベースまたはネットワーク呼び出し(HTTP)で機能するのか、それともファイルIOでのみ使用されるのかわからない。

だから問題は、私の理解では正しいのかということです。私が間違って表現した特定のものはありますか?

4

2 に答える 2

61

TaskCompletionSourceTaskコードを実行しないオブジェクトを作成するために使用されます。

これらは、Microsoftの新しい非同期APIによってかなり使用されています-I / Oベースの非同期操作(またはタイムアウトなどの他の非CPUベースの非同期操作)があるときはいつでも。また、async Task作成するメソッドはすべて、TCSを使用して返されたを完了しTaskます。

インスタンスを作成するさまざまな方法について説明しているブログ投稿「タスクの作成」があります。/パースペクティブ(TPLパースペクティブではない)Taskから記述されていますが、ここでも適用されます。asyncawait

StephenToubの優れた投稿も参照してください。

于 2012-05-02T19:06:55.710 に答える
8

http://tutorials.csharp-online.net/TaskCompletionSourceで提供された説明が好きです

(申し訳ありませんが、リンクは現在死んでいる可能性があります)

最初の2つの段落は以下のとおりです

Task.Runが、プールされた(またはプールされていない)スレッドでデリゲートを実行するタスクを作成する方法を見てきました。タスクを作成する別の方法は、TaskCompletionSourceを使用することです。

TaskCompletionSourceを使用すると、しばらくしてから開始および終了する操作からタスクを作成できます。これは、手動で運転する「スレーブ」タスクを提供することで機能します。つまり、操作がいつ終了するか、または障害が発生したかを示します。これは、I / Oバウンドの作業に最適です。操作中にスレッドをブロックすることなく、タスクのすべての利点(戻り値、例外、および継続を伝播する機能を備えています)を取得できます。

TaskCompletionSourceを使用するには、クラスをインスタンス化するだけです。他のタスクと同様に、待機して継続をアタッチできるタスクを返すTaskプロパティを公開します。ただし、タスクは、次のメソッドを介してTaskCompletionSourceオブジェクトによって完全に制御されます。

public class TaskCompletionSource<TResult> 
{ 
 public void SetResult(TResult result); 
 public void SetException (Exception exception); 

 public void SetCanceled();   
 public bool TrySetResult (TResult result); 
 public bool TrySetException (Exception exception); 
 public bool TrySetCanceled();
 ... 
}

これらのメソッドのいずれかを呼び出すと、タスクが完了、障害、またはキャンセルされた状態になります(後者については「キャンセル」のセクションで説明します)。これらのメソッドのいずれかを1回だけ呼び出すことになっています。もう一度呼び出すと、SetResult、SetException、またはSetCanceledは例外をスローしますが、Try*メソッドはfalseを返します。

次の例では、5秒間待機した後に42を出力します。

var tcs = new TaskCompletionSource<int>();
new Thread (() =>     {
                       Thread.Sleep (5000); 
                       tcs.SetResult (42); 
                      })    
           .Start();   
Task<int> task = tcs.Task;    // Our "slave" task. 
Console.WriteLine(task.Result);  // 42

その他の興味深い引用

TaskCompletionSourceの真の力は、スレッドを拘束しないタスクを作成することです。

..以降

スレッドなしでTaskCompletionSourceを使用するということは、5秒後に継続が開始されたときにのみスレッドが使用されることを意味します。エラーや過度のリソース消費なしに、これらの操作を一度に10,000回開始することで、これを実証できます。

于 2014-04-09T14:25:22.397 に答える