web-dev-qa-db-ja.com

TPLとasync / awaitの違い(スレッド処理)

スレッド作成に関しては、TPLとasync/awaitの違いを理解しようとしています。

TPL(TaskFactory.StartNew)は、スレッドプール内のスレッドの作業をキューに入れるという点で、ThreadPool.QueueUserWorkItemと同様に機能すると考えています。もちろん、新しいスレッドを作成するTaskCreationOptions.LongRunningを使用しない限りです。

async/awaitは同様に機能するので、本質的には次のように考えました。

TPL:

Factory.StartNew( () => DoSomeAsyncWork() )
.ContinueWith( 
    (antecedent) => {
        DoSomeWorkAfter(); 
    },TaskScheduler.FromCurrentSynchronizationContext());

Async/Await

await DoSomeAsyncWork();  
DoSomeWorkAfter();

同じになります。私が読んでいたものから、それはasync/awaitのように思えます。それで、いつ新しいスレッドを作成し、いつ新しいスレッドを作成しませんか? IO完了ポートを扱っている場合、新しいスレッドを作成する必要がないことがわかりますが、そうでない場合は必要になると思います。FromCurrentSynchronizationContextの私の理解は常に私はいつも本質的にUIスレッドだと思いました。

60
coding4fun

TPL(TaskFactory.Startnew)は、スレッドプール内のスレッドの作業をキューに入れるという点で、ThreadPool.QueueUserWorkItemと同様に機能すると考えています。

かなり

私が読んでいると、async/awaitのみが「時々」新しいスレッドを作成するようです。

実際、それは決してありません。マルチスレッドが必要な場合は、自分で実装する必要があります。 Task.Runの短縮形である新しいTask.Factory.StartNewメソッドがあり、これはおそらくスレッドプールでタスクを開始する最も一般的な方法です。

IO完了ポートを扱っている場合、新しいスレッドを作成する必要がないことがわかりますが、それ以外の場合は必要になると思います。

ビンゴ。したがって、Stream.ReadAsyncなどのメソッドは、IOCPの周りにTaskラッパーを実際に作成します(StreamにIOCPがある場合)。

いくつかの非I/O、非CPU「タスク」を作成することもできます。簡単な例はTask.Delayで、一定期間後に完了するタスクを返します。

async/awaitの素晴らしい点は、スレッドプール(たとえば、Task.Run)にいくつかの作業をキューに入れ、I/Oにバインドされた操作(たとえば、Stream.ReadAsync)を実行できることです。操作(例、Task.Delay)...そしてそれらはすべてタスクです!それらは待つか、Task.WhenAllのような組み合わせで使用できます。

Taskを返すメソッドはawaitedにすることができます-asyncメソッドである必要はありません。したがって、Task.DelayおよびI/Oバインド操作はTaskCompletionSourceを使用してタスクを作成および完了します。スレッドプールで行われるのは、イベントが発生したときの実際のタスク完了(タイムアウト、I/O完了など) )。

FromCurrentSynchronizationContextの私の理解も常に少し曖昧だったと思います。私はいつも、本質的にUIスレッドだと考えていました。

SynchronizationContext記事 を書きました。ほとんどの場合、SynchronizationContext.Current

  • 現在のスレッドがUIスレッドの場合、UIコンテキストです。
  • 現在のスレッドがASP.NET要求を処理している場合、ASP.NET要求コンテキストです。
  • それ以外の場合は、スレッドプールコンテキストです。

すべてのスレッドcan独自のSynchronizationContextを設定するため、上記のルールには例外があります。

デフォルトのTask awaiterは、現在のasyncSynchronizationContextメソッドの残りをスケジュールすることに注意してくださいnullでない場合;それ以外の場合は、現在のTaskSchedulerに進みます。これは今日ではそれほど重要ではありませんが、近い将来、重要な区別になるでしょう。

私は自分のブログに async/await intro を書きました。最近、Stephen Toubが優れた async/await FAQを投稿しました

「並行性」対「マルチスレッド」については、 this related SO question 。を参照してください。asyncは並行性を有効にします。 await Task.WhenAllまたはawait Task.WhenAnyを使用して並行処理を行うのは簡単です。また、スレッドプール(Task.RunまたはConfigureAwait(false)など)を明示的に使用しない限り、同時に複数の並行操作を実行できます(たとえば、複数のI/OまたはDelayなどの他のタイプ-それらに必要なスレッドはありません。この種のシナリオでは「シングルスレッド同時実行」という用語を使用しますが、ASP.NETホストでは、実際には "zero-threaded concurrency"になります。

74
Stephen Cleary

async/awaitは基本的にContinueWithメソッドを簡素化します( Continuation Passing Style の継続)

それは並行性を導入しません-あなたはまだそれを自分でしなければなりません(またはフレームワークメソッドの非同期バージョンを使用します。)

したがって、C#5バージョンは次のようになります。

await Task.Run( () => DoSomeAsyncWork() );
DoSomeWorkAfter();
8
Nicholas Butler