2015-09-24 18 views
6

非同期の場合に最適なアプローチが不思議です。最初は私のコードはこのように見えました(例は単純化されています)。.Net Async ContinueWith VSタスクに埋め込みタスクを含める

public NotificationSummary SendNotification() 
{ 
     var response = new NotificationSummary(); 
     var first = FindSubscriptions(1); 
     ... 
     var seventh = FindSubscriptions(7); 

     Task.WaitAll(first, ... , seventh); 

     response.First = first.Result; 
     ... 
     response.Seventh = seventh.Result; 
     return response; 
} 


private Task<NotificationResult> FindSubscriptions(int day) 
{ 
    return Task.Run(() => 
    { 
     var subscriptions = // call to database to get list of subscriptions 
     var tasks = subscriptions.Select(x => SendOutNotification(x)) 
     var results = Task.WhenAll(tasks).Result.ToList(); 
     return // map results to NotificationResult 
    } 
} 


private Task<IndividualResult> SendOutNotification(Subscription subscription) 
{ 
    return Task.Run(() => 
    { 
     var response = new IndividualResult(); 
     foreach(var user in subscription.Users) 
     { 
      try 
      { 
       // Send user info to EMAIL API 
       response.Worked.Add(user); 
      } 
      catch(Exception ex) { response.Failed.Add(user)} 
     } 

     return response; 
    } 
} 

しかし、このアプローチは、単一の責任に違反していると、彼らは、このコードが何をしているかを把握しようとしてくるときに、それは他の開発者に混乱するかもしれません。私は仕事をつなぎ合わせる方法を見つけようとしていました。私はContinueWithに出くわしました。私はいくつかの研究を行いました(別のスタックオーバーフロー記事を見ました)、私はContinueWithに関する複数のレビューを受け取ります。私は実際にSendNotificationメソッドをこのようにしたいと思いますが、これが非同期とタスクになると良いアプローチであるかどうかはわかりません。

public NotificationSummary SendNotification() 
{ 
    var response = new NotificationSummary(); 
    var firstTasks = new List<IndivdualResult>(); 
    var first = FindSubscriptions(1).ContinueWith(x=> 
        x.Result.ForEach(r => 
        firstTasks.Add(SendOutNotification(x).Result))); 
    response.First = // map first; 

    // do 2 - 7 tasks as well 

    return response; 
} 

private Task<List<Subscription>> FindSubscriptions() {} //returns subscriptions 

private Task<IndividualResults> SendOutNotication() {} // same as above 

これらのアプローチのどちらが「正しい方法」と考えられるのでしょうか?

+1

あなたは常にタスクを同期的にブロックしています。これは、最初にそれらの操作を非同期にする目的を打ち負かしています。操作が非同期である必要がない場合は、それらを同期させて開始してください。実際に非同期にする必要がある場合は、同期が完了するまで待つ必要はありません。 – Servy

+0

これはなぜSRPに違反していますか? – usr

+0

@サービーあなたは何を意味するのか分かります。だから、私は本当にすべてのタスクを開始し、その後、結果を打ち始めるwaitall機能を持っている必要があります。 – Beastwood

答えて

5

ContinueWithawaitが利用可能になったのでコードの匂いです。 awaitは、基本的に継続を付ける良い方法です。

コードの最初のバージョンには構造的な問題はありません。あなたは、おそらく必要があります。

  • はTask.Runが

を新しい非同期メソッドでContinueWithを交換し、待つWhenAll

  • はのawaitとWaitAllを置き換える建物内の企業削除await
  • ですべてWait/Result呼び出しを置き換えますこれは、混乱をクリーンアップし、効率の問題を修正する必要があります。

    並列処理が不要な場合は、すべてを同期させることもできます。