2013-05-21 17 views
5

According to MSDNasyncawaitせずに待っています:理解非同期は/新しいスレッドを作成していないスレッド

asyncawaitキーワードは、追加のスレッドが作成されることはありません。

これを念頭に置いて、いくつかの簡単なプログラムの制御フローを理解するのが難しいです。私の完全な例は以下の通りです。 NuGetからインストールできるDataflow libraryが必要です。

using System; 
using System.Threading.Tasks.Dataflow; 

namespace TaskSandbox 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      BufferBlock<int> bufferBlock = new BufferBlock<int>(); 

      Consume(bufferBlock); 
      Produce(bufferBlock); 

      Console.ReadLine(); 
     } 

     static bool touched; 
     static void Produce(ITargetBlock<int> target) 
     { 
      for (int i = 0; i < 5; i++) 
      { 
       Console.Error.WriteLine("Producing " + i); 
       target.Post(i); 
       Console.Error.WriteLine("Performing intensive computation"); 
       touched = false; 
       for (int j = 0; j < 100000000; j++) 
        ; 
       Console.Error.WriteLine("Finished intensive computation. Touched: " + touched); 
      } 

      target.Complete(); 
     } 

     static async void Consume(ISourceBlock<int> source) 
     { 
      while (await source.OutputAvailableAsync()) 
      { 
       touched = true; 
       int received = source.Receive(); 
       Console.Error.WriteLine("Received " + received); 
      } 
     } 
    } 
} 

出力:

これは forループの実行中に OutputAvailableAsyncタスクが完了するよう Consumeは、制御を与えていることを示していると思われる
Producing 0 
Performing intensive computation 
Received 0 
Finished intensive computation. Touched: True 
Producing 1 
Performing intensive computation 
Received 1 
Finished intensive computation. Touched: True 
Producing 2 
Performing intensive computation 
Received 2 
Finished intensive computation. Touched: False 
Producing 3 
Performing intensive computation 
Received 3 
Finished intensive computation. Touched: False 
Producing 4 
Performing intensive computation 
Received 4 
Finished intensive computation. Touched: True 

for (int j = 0; j < 100000000; j++) 
    ; 

これはで驚くだろうスレッドモデル。しかし、追加のスレッドが含まれていない場合、どのようにforループの途中でProduceの制御を行うことができますか?

+0

@ I4V:この質問に対する答えは、「すべてのブロック操作が明示的に非同期/待機モデルを使用して制御を行う必要がある」と述べています。しかし、私の質問では、コントロールは明示的に制御を行う「生産」なしで、「生産」から「消費」に移行します。それは私が混乱している部分です。 –

+3

@Matthewこれはコンソールアプリケーションであるため、 'SynchronizationContext'はありません。つまり、' await'呼び出しからのコールバックはすべてスレッドプールである 'SynchronizationContext.Default'に移動するので、実際には2つのスレッドが実行されていますこのプログラムの実行中に時々。追加のスレッドが作成されないようにするには、独自のカスタム同期コンテキストを作成して設定する必要があります。もしあなたがそうしたなら、あなたは生産中にコントロールを得ていないので、すべての生産が具体的に行われるまで、 'Recieved'コールが呼び出されないことが分かります。 – Servy

+0

@Servy:複数のスレッドが関与している場合、MSDNは「特に、競合状態を防ぐ必要がないため、このアプローチはIOバインド操作ではBackgroundWorkerよりも優れています」と主張しています。簡単な競合条件を追加するために私の例を編集しました。 –

答えて

-1

制御処理は同じスレッド内で行われるため、ループが実行されているときにはConsumeメソッドは使用されず、その逆もあります。スレッドを使用していた場合は必ずしもそうであるとは限りません。実際には両方とも同時に実行することを期待しています。

同じスレッド内にあるということは、コントロールがコードの一部から別のコントロールに渡すことができないことを意味するものではありません。 .NET(および他のすべてのフレームワーク、AFAIK)はスムーズに処理し、各部分は問題なく独自のコンテキストで実行されます。

しかし、両方のスレッドを1つのスレッドで実行すると、Consumeが実行されている間にループがハングすることになります。 Consumeに時間がかかりすぎると、それはまさにユーザーが知覚するものです。そのため、Windowsフォームに慣れていないプログラマーの多くは、あまりにも多くの情報を一度にGUIコントロールに入力すると、フォームがハングアップしたり、時には空白になることに驚いています。画面をリフレッシュするスレッドは、バックグラウンドワーカースレッドを使用していません。

+0

明示的にコントロールを生成する '' Produce''なしで '' Consume''に制御を渡す原因は何ですか? .NETは、 'Produce'が長い間実行されており、' Consume'(スレッドモデルのOSの役割に似ています)を制御することを通知しますか? –

+0

実際、私はServyのコメントが私のものよりも良いと思う。 – Renan

2

スレッドが追加されていない場合、forループの途中で歩留まり制御をどのように作成できますか?

追加のスレッドは関係していないと言われた人は誰ですか?あなたが述べた事実は次のとおりです:

asyncキーワードとawaitキーワードでは、追加のスレッドが作成されません。

これは絶対に当てはまります。あなたのプログラムは

target.Post(i); 

await source.OutputAvailableAsync()) 

私の推測では、target.Post(i)source.OutputAvailableAsync()への呼び出しがスレッドを作成したことだろうフラグメントを含みます。awaitはスレッドを生成しません。すべてawaitであり、メソッドの残りを呼び出しによって返されたタスクの継続として割り当て、呼び出し元に制御を返します。そのタスクがスレッドを生成して作業を行う場合、それはビジネスです。

awaitは、もう1つの制御フローです。それにもかかわらず、制御フローは非常に複雑な制御フローになります。スレッドを作成するための構文的な砂糖ではありません。それはタスクに継続を割り当てるための構文的な砂糖です。

+4

実際に、それらの呼び出しのどちらもスレッドを作成しません。 @Servyは、 'await'演算子(より具体的には、' await'演算子によって生成されたコードによって使用されるタスク待ち時間)がデフォルトの 'SynchronizationContext'を使用してスレッドプールスレッド上のメソッド継続をスケジュールするという点で正しいです。 –

+0

@StephenCleary:ああ、いいです。メモをありがとう。 –

関連する問題