2017-11-10 6 views
3

ConfigureAwait()をいつ使うべきかを理解しようとしています。予約する Accordin:ConfigureAwaitの理解

When an async method resumes after an await, by default it will resume executing within the same context. This can cause performance problems if that context was a UI context and a large number of async methods are resuming on the UI context. 
    Solution 
To avoid resuming on a context, await the result of ConfigureAwait and pass false 
for its continueOnCapturedContext parameter: 

async Task ResumeWithoutContextAsync() 
{ 
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); 

// This method discards its context when it resumes. 
} 

文脈とどのようにConfigureAwaitを(参照することです何が)サンプルアプリケーションで物事を変更します。

static async Task ResumeWithoutContextAsync() 
    { 
     await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(true); 
     Console.WriteLine("ManagedThreadId {0}", Thread.CurrentThread.ManagedThreadId); 

     // This method discards its context when it resumes. 
    } 

    static void Main(string[] args) 
    { 

     ResumeWithoutContextAsync(); 

     Console.ReadLine(); 

    } 

私はそのコンテキストを考えていたスレッドですが、そうではありません。

+0

「ブロッキング」という用語があります。一部のメソッドは、作業が同期(ブロック)されたときに戻り、他のメソッドは非同期(非ブロック)であり、すべての作業が完了する前に戻ります。メソッドが非ブロッキングであり、すべての作業が完了するまで待つ必要がある場合は、待機する必要があります。 – jdweng

+0

https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html – peco

答えて

1

ここでのコンテキストはSynchronizationContextです。 Awaitは、現在のコンテキスト(SynchronizationContext.Current)が存在し、ConfigureAwait falseを使用しなかった場合、継続(残りのメソッドの残りの部分)を現在のコンテキスト(SynchronizationContext.Current)にポストします。継続がコンテキストに通知されない場合、スレッドプールスレッド上で実行されます。コンソールアプリケーションでは、デフォルトでシンタナライゼーションコンテキストが存在しないため、テストではConfigureAwaitは無効です。あなたはその継続がに投稿されましたが表示されます - ConfigureAwait(true)(またはまったくなし)で

SynchronizationContext.SetSynchronizationContext(new MySynchornizationContext()); 

Main方法の初めに続いて

class MySynchornizationContext : SynchronizationContext { 
    public override void Post(SendOrPostCallback d, object state) { 
     Console.WriteLine("posted"); 
     base.Post(d, state); 
    } 

    public override void Send(SendOrPostCallback d, object state) { 
     Console.WriteLine("sent"); 
     base.Send(d, state); 
    } 
} 

:あなたはしかし、効果を確認するためにダミーのコンテキストを作成することができますコンテキスト(コンソールの "posted"行)。 ConfigureAwait(false)と - あなたはそれが表示されません。

実際の同期コンテキストは当然複雑です。たとえば、winformsやWPFのようなUIコンテキストは、継続を「キュー」して1つのUIスレッドで実行します。あなたの質問引用文に説明されているように問題があるかもしれませんが、デッドロックにつながる可能性があります。汎用ライブラリを書くときには、この動作を避けるためにConfigureAwait(falseを使うのが有益です。

SynchronizationContextすべてのコールバックを1つのスレッドにポストする必要はありませんが、それは何でもできます。たとえば、ASP.NET MVCコンテキスト(古いバージョン以上)は、要求スレッドにコールバックをポストします。多くの要求が非常に多くのスレッドを要求する可能性があります。