2015-09-15 7 views
9

私は同じようにいくつかのコードに出くわした:は `async`ラムダを` Task.Run() `と冗長に使用していますか?

var task = Task.Run(async() => { await Foo.StartAsync(); }); 
task.Wait(); 

(いいえ、私はFoo.StartAsync()の内部動作を知りません)。私の最初の反応はとasync/awaitを取り除くと書き換えますされます:

var task = Foo.StartAsync(); 
task.Wait(); 

それは(約Foo.StartAsync()全く何も知らない、再び)が正しいか、ではないだろう。 This答えがWhat difference does it make - running an 'async' action delegate with a Task.Run ...の場合がありますが、それは意味をなさない場合がありますが、「真実を伝えるためには、多くのシナリオを見たことがありません...」

+2

どちらの場合でも、 'Task.Wait'と同時に待つのではなく、' await'する必要があります。 – i3arnon

答えて

10

が通常Task.Runため使用を意図し、非UIスレッドでCPUに結合したコードを実行することです。そのため、asyncデリゲートで使用することは非常にまれですが、非同期部分とCPUバインド部分の両方を持つコードの場合など、可能です。

しかし、それは意図した使い方です。私はあなたの例で考える:

var task = Task.Run(async() => { await Foo.StartAsync(); }); 
task.Wait(); 

それは原作者が(私は私のブログで説明するように)Task.Runavoid deadlocks common in that situationにを使用して、同期非同期コードをブロックしようとすると、(A-B)であることをはるかに可能性があります。

本質的には、私がarticle on brownfield asynchronous codeで説明している「スレッドプールのハック」のように見えます。

最高ソリューションはTask.RunまたはWaitを使用しないことです。

await Foo.StartAsync(); 

これが最善のアプローチである、あなたのコードベースを介して、成長しasyncが発生しますが、許容できない量のを引き起こす可能性があり今すぐあなたの開発者のために働いてください。これはおそらく前任者がTask.Run(..).Wait()を使用した理由です。

+2

"async'があなたのコードベースで成長する"という考えは、どこかで 'IDisposable'を導入したときと同じように聞こえます'IDisposable'の使用が適切です)。 –

+2

@ダン:はい、 'IDisposable'と' async'の間で非常によく似た設計上の問題があります。 –

4

ほとんどはいです。

このようにTask.Runを使用すると、非同期メソッドの実行方法を理解していない人が主に使用します。

ただし、違いがあります。 Task.Runを使用すると、ThreadPoolスレッドで非同期メソッドを開始することを意味します。

これは、非同期メソッドの同期部分(最初の待機前の部分)が充実し、呼び出し側がメソッドがブロックしていないことを確認したい場合に便利です。

これは、現在のコンテキストを「出る」ためにも使用できます。たとえば、SynchronizationContextがない場合などです。

+0

ThreadPoolスレッドで 'Foo.StartAsync()'を実行することが重要だったのと同じように、その旨のコメントが欲しいですか? –

+1

@ダン私はそれを言わないでしょう。また、メソッド自体の問題も少なくなります。これは発信者の問題かもしれません。あなたのスレッドが「特別」(UIスレッド、またはリクエストを待っている)で、他のスレッドにできるだけ負荷をかけたい場合は、 'Task.Run'を使用してください。 – i3arnon

+0

だから、推奨される方法はTask.Runの中で非同期で待つべきですか? –

関連する問題