2017-12-05 17 views
-1

TPL Dataflowをよく理解するための簡単なプログラムを作成しようとしています。私はそれが完了している場合、データフローブロックを再起動する長期実行タスクを作成しようとしています。フォールトステートでActionBlockが完了しない

私の現在のRestartActionBlockタスクは、 "-1"と入力してブロックを完全に呼び出すと、ActionBlockの完了を待つことができます。しかし、ブロックをフォルトするための例外を発生させようとしたり、ブロックFault()インタフェースメソッドを呼び出すと、ActionBlockの完了タスクは完了しません。この状況では、await singleTestFlow.Completion;コールは決して続かない。

例外を発生させた後、またはFault()メソッドを呼び出した後、プログラムに別の入力を入力し、ブロックがフォールト状態になっていることを確認するコードをデバッグすることによって、ブロックがフォルト状態になっていることを確認できます:ブロックが故障状態にある場合は、なぜawait singleTestFlow.Completion;

ActionBlock in the faulted state

返すことはありませんでしたか?故障したブロックのデバッグスクリーンショットが撮影された場所

class Program 
{ 
    private static ActionBlock<string> singleTestFlow; 

    static void Main(string[] args) 
    { 
     //start thread that should restart a completed action block 
     Task.Run(RestartActionBlock); 

     Console.WriteLine("Enter -0 to exit, -1 to complete flow, -0- to throw an exception, Anything else otherwise"); 
     var input = Console.ReadLine(); 

     //allow user to input text until "-0" is entered 
     while (!input.Equals("-0")) 
     { 
      if (input.Equals("-1")) 
      { 
       singleTestFlow.Complete(); 
      } 

      singleTestFlow.Post(input); 

      input = Console.ReadLine(); 
     } 

     async Task RestartActionBlock() 
     { 
      var iterations = 0; 
      while (true) 
      { 
       singleTestFlow = new ActionBlock<string>(s => 
       { 
        if (s.Equals("-0-")) 
        { 
         //throw new Exception("Something went wrong in here"); 
         ((IDataflowBlock)singleTestFlow).Fault(new Exception("Something went wrong in here")); 
        } 
        Console.WriteLine($"{iterations}: " + s); 

       }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }); 

       await singleTestFlow.Completion; 

       var completionTask = singleTestFlow.Completion; 

       var message = $"action block: {iterations} "; 
       switch (completionTask.Status) 
       { 
        case TaskStatus.RanToCompletion: 
         message += "ran to completion"; 
         break; 
        case TaskStatus.Canceled: 
         message += "was canceled"; 
         break; 
        case TaskStatus.Faulted: 
         message += "has faulted"; 
         Console.WriteLine(completionTask.Exception); 
         break; 
       } 
       Console.WriteLine(message); 
       iterations++; 
      } 
     } 
    } 


} 

Sample Console Entry 私は入力されたコンソールでのポイントは、「EEE」です。

答えて

2

は、ここで簡単な修正です:

は、上記避けているん何

await Task.WhenAny(singleTestFlow.Completion); 

または

await singleTestFlow.Completion.ContinueWith(_ => { }); 

await singleTestFlow.Completion; // Throws if Completion is faulted, breaking your loop. 

を交換しCompletionタスク例外を伝播しています。これにより、あなたの意図通りにあなたのRestartActionBlockループを永遠に実行することができます(ブロック障害の直後に死ぬこととは対照的に)。

理想的には、しかし、あなたは次の2つのステートメントの戻り値を無視すべきではありません。

Task.Run(RestartActionBlock); // Unobserved Task. Usually a bad idea. 

singleTestFlow.Post(input); 

あなたは上記の戻り値を観測していた場合、あなたは」実際にあなたのActionBlock<string>の不具合が解消されたらすぐに助けを求めて叫び始めます。

タスクはすぐawait singleTestFlow.CompletionスローとしてFaulted状態にTask.Run(RestartActionBlock)遷移によって返された - しかし、あなたが言ったタスクへの参照を保持する、またはその状態を確認していないので、あなたは、通知されることはありません飽きません。

同様に、ActionBlock<string>の直後に、singleTestFlow.Post(input)を呼び出すと、実際にはfalseが返されます。つまり、ブロックされたアイテムはブロックされません。それらは単に破棄されます。

+0

大変ありがとうございました!それは今働いている。あなたの答えから、2つの新しい質問があります。 'singleTestFlow.Completion'と' Task.WhenAny(singleTestFlow.Completion) 'を待つ間の違いは何ですか?後者は私のコードを動作させるが、私はその違いを理解していない。次に、 'Task.Run(RestartActionBlock)'から返されたタスクをどのように使用できますか?私は、メインでコードの残りの部分を続ける必要があるので、その完了を待つ必要はありません。 – Slvrfn

+0

'RestartActionBlock'タスクを永久に実行させたい場合は、包括的な例外処理が組み込まれていることを確認する必要があります。' await singleTestFlow.Completion'が例外をスローした場合(ブロック障害のため)、 'RestartActionBlock'は直ちに戻ります同期方法とよく似ています)。それは決して「待ち」を超えて進展しません。 'Task.WhenAny'は、最初に完了した(または失敗した)タスクへの参照を返すだけなので、回避することができます。例外を再スローしません。その効果は 'await singleTestFlow.Completion'の周りに' try/catch'を置くのと似ています。 –

+0

'Task.Run(RestartActionBlock) 'によって返された' Task'への参照を保持していたのであれば、ある時点でFaulted状態に移行し、 'RestartActionBlock'ループが停止していなければならないことがわかります。これはデバッグに役立ちます。事実、問題を診断するために私が個人的にどのように成功したかは、まさにその通りです。 –

関連する問題