2016-06-01 5 views
-1
public int CalcGroup(CancellationTokenSource cts) 
{ 
    try 
    { 
     CancellationToken ct = cts.Token; 
     if (cts.IsCancellationRequested == true && TaskWorkStatus.IsContinue == false) return 0; 

     for (int i = 0; i < _paralellTaskCount; i++) 
     { 
      int counter = CheckCounter(message); 
      if (counter >= 0) 
      { 
       var myTask = new Task<long>(() => CalcSingle(_personnelIds[counter].Item1), ct, TaskCreationOptions.LongRunning); 
       if(myTask.IsCompleted) 
        myTask.ContinueWith(t => CalcSingle(_personnelIds[counter].Item1), ct); 
       else 
        myTask.Start(); 

      } 
     } 
    } 
    catch (Exception) 
    { 
     return 0; 
    } 
    return 1; 
} 

上記のコードブロックでは、CanceledCompletedのタスクを実行したいが、動作しません。
私の間違いは何ですか?完了したタスクを続けるには?

+0

async awaitを使用したくない理由はありますか? –

答えて

1

0)コンストラクタを使用して新しいタスクを作成することは、それを実行すると余分なオーバーヘッドが発生するため、悪い習慣です(理由と方法は後で説明します)。 .NETバージョンに応じて、Task.RunまたはTask.Factory.StartNewを使用します(私は最近、Task.Runが.NET 4.5以降の方が優れていることを学びました)。

1)タスクを作成しても起動しないため、現在のロジックは常に最初の条件をスキップしてタスクを開始し、継続は発生しません。

2)タスクを開始しても、条件チェックに時間がかかることを保証するものではありません。これはTask.ContinueWithがTaskContinuationOptions列挙を受け入れるオーバーロードを持っている理由です。OnlyOnRanToCompletionを持っており、 OnlyOnFaulted、など。

3)ここでは、それをまとめるためにあなたのコードでは、継続は、それが継続するタスクである先行タスクを、受け取ることに注意してください(

for (int i = 0; i < _paralellTaskCount; i++) 
     { 
      object message; 
      int counter = CheckCounter(message); 

      if (counter >= 0) 
      { 
       var task = Task.Run(() => CalcSingle(_personnelIds[counter].Item1)); 
       var continuation = task.ContinueWith((antecedent) => CalcSingle(_personnelIds[counter].Item1), 
        TaskContinuationOptions.OnlyOnRanToCompletion); 

      } 
     } 

少し微調整した後、あります。 。

4)どのようなタスクでも例外が発生していないかどうかはチェックされていないようです。try catch節でその文をラップすると例外はスレッドに転送されません。 ResultまたはExceptionプロパティにアクセスするには、Wait()を呼び出すか、awaitキーワードを使用してそれを達成します。

5)ここで同じことを非同期実装であり、例外

for (int i = 0; i < _paralellTaskCount; i++) 
     { 
      try 
      { 
       object message; 
       int counter = CheckCounter(message); 

       if (counter >= 0) 
       { 
        long res1 = await Task.Run(() => CalcSingle(_personnelIds[counter].Item1)); 
        long res2 = await Task.Run(() => CalcSingle(_personnelIds[counter].Item1)); 
       } 
      } 
      catch (AggregateException e) 
      { 
       //TODO handle 
      } 
     } 

6)のためのチェックが、あなたがいくつかの非常に重要な概念を逃したようだとして、TPLを考えていくつかの記事を読んでください。

+2

タスクコンストラクタにはオーバーヘッドがありません。その結果、よりクリーンでエラーの発生が少ないコードになります。 – Servy

+0

コンストラクタを使用してタスクを作成しても特別なオーバーヘッドはありませんが、この方法でタスクを作成すると後でオーバーヘッドが発生します。タスクは一度しか開始できないため、タスクを作成して開始すると、タスクは既に開始しているかどうかをチェックします。この情報はインスタンス内に必ずしも存在しないため、オーバーヘッドが発生する可能性があります。この問題は、TPLをカバーするコースで提示されます。 –

+0

そのコードに関するすべての問題のうち、タスクが既に実行されているかどうかを確認するのに費やされる時間は、リスト上でかなり低くなければなりません。ゼロではないかもしれませんが、ほぼ確実に問題にはなりません。 – Servy

関連する問題