2016-06-12 15 views
3

ConfigureAwaitでちょっと試しています。私はそれがどのように機能するのか理解したいからです。ConfigureAwaitは非スレッドプールスレッドにのみ影響しますか?

void Main() 
{ 
    // Use dispatcher to execute the code on STA thread 
    Dispatcher.CurrentDispatcher.Invoke(() => Run()); 
} 

private async static Task Run() 
{ 
    var continueOnCapturedContext1 = true; 
    var continueOnCapturedContext2 = true; 

    PrintThreadID(); 
    await Task.Run(() => PrintThreadID()).ConfigureAwait(continueOnCapturedContext1); 
    PrintThreadID(); 
    await Task.Run(() => PrintThreadID()).ConfigureAwait(continueOnCapturedContext2); 
    PrintThreadID(); 
} 

private static void PrintThreadID() 
{ 
    Console.Write(Thread.CurrentThread.ManagedThreadId.ToString("00") + "\t"); 
} 

そして、私は次の出力ました:

Therfore、私は(実際にはLINQPadで実行されている)以下の小さなコンソールアプリケーションを書いた

A)の真/真

var continueOnCapturedContext1 = true; 
var continueOnCapturedContext2 = true; 

1)11 19 11 07 11

予想

2)11 09 11 12 11

3)11 06 11 06 11

:ディスパッチャスレッド(11)を捕捉したとawaitableタスクは、異なるまたは同一のスレッドプールのスレッドで実行されました。 FALSE FALSE

B)/

var continueOnCapturedContext1 = false; 
var continueOnCapturedContext2 = false; 

1)11 23 23 22 22

2)11 19 19 19 19

3)11 10 10 10 10

また、SynchronizationContextはcaそれに続く待ち受け可能で非待ち受けのコードがスレッドプールスレッド(通常は同じ)上で実行されました。

C)真/偽

var continueOnCapturedContext1 = false; 
var continueOnCapturedContext2 = true; 

1)

2)11 20 20 20 20

3)

出力1と出力3の結果が奇妙です。 2. awaitbaleタスクは、キャプチャされたコンテキストで続行するオプションで実行されたので、呼び出されたコードと同じスレッドで実行されることが期待されます。

ConfigureAwait(true/false)は、以前に呼び出されたことがある次の待ち受け可能な呼び出しには影響しないようです。

+1

synccontextは、好きなことを行うことができます。それは、コインの裏返しにもかかわらず、あなたのコードをどんなスレッドでも実行することができます。したがって、*よく使われるコンテキストが何をするのかを理解することは重要です。 ConfigureAwait(false)は単に「存在する場合でもコンテキストを使用しない」と言うだけです。 – usr

答えて

10

2. awaitbaleタスクは、「キャプチャされたコンテキストで続行する」オプションで実行されたので、呼び出されたコードと同じスレッド上で実行されることが期待されます。

「context == thread」と仮定していますが、そうではありません。スレッドプールを使用する同期コンテキストは、のスレッドプール内の任意のスレッドで再開します。あなたがの場合、は同期コンテキストをキャプチャしないと、 "スレッドプールのスレッド"になります。

スレッドプールスレッドを既に使用している場合は、同期コンテキストをキャプチャするかどうかは関係ありません。継続はスレッドプールスレッドで終了します。しかし、複数のスレッドと異なる同期コンテキストを持つことは完全に合理的であり、同期コンテキストをキャプチャするとという1つのスレッドが返されますが、必ずしも同じである必要はありません。

ConfigureAwait(true/false)は、それ以前にすでに呼び出されていた場合、それに続く待ち受け可能な呼び出しには影響しないようですが、そうですか?

かなりです。タスクで継続を使用する必要がある場合は、そのようになります。 ConfigureAwaitを呼び出した最初のタスクが既に完了している場合、コードは同期して実行され続けます。その時点で、第2のConfigureAwaitが重要です。

例:

using System; 
using System.Windows.Forms; 
using System.Threading; 
using System.Threading.Tasks; 

class Test 
{  
    static void Main() 
    { 
     var form = new Form(); 
     form.Load += async (sender, args) => 
     { 
      Console.WriteLine(Thread.CurrentThread.ManagedThreadId); 
      await Task.FromResult(10).ConfigureAwait(false); 
      Console.WriteLine(Thread.CurrentThread.ManagedThreadId); 
      await Task.Delay(1000).ConfigureAwait(false); 
      Console.WriteLine(Thread.CurrentThread.ManagedThreadId); 
     }; 
     Application.Run(form); 
    } 
} 

サンプル出力:

1 
1 
5 

Task.FromResultが既に完了したタスクを返すためだから第Console.WriteLineは、ConfigureAwait(false)にもかかわらず、それでもコードが同じスレッド上で実行されたことを示しました。

+0

良い良い良い+1 –

関連する問題