2015-09-24 9 views
6

Basta chiedersi l'approccio migliore quando si tratta di asincrono. All'inizio il mio codice sembrava questo (l'esempio è semplificato).. Async Continua con VS Incorporamento delle attività in attività

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; 
    } 
} 

Ma questo approccio sta violando singola responsabilità e potrebbe essere fonte di confusione per altri sviluppatori quando vengono provano a capire che cosa questo codice sta facendo. Stavo cercando di trovare un modo per concatenare i compiti e mi sono imbattuto in ContinueWith. Ho fatto qualche ricerca (aka guardato altri post StackOverflow) e ottengo recensioni contrastanti su ContinueWith. Mi piacerebbe davvero che il mio metodo SendNotification assomigliasse a questo, ma non so se questo è un buon approccio quando si tratta di async e tasking.

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 

Mi chiedo quale di questi approcci sarebbe considerato il "modo giusto" se entrambi?

+1

Si sta costantemente bloccando in modo sincrono le attività, il che sta vanificando lo scopo di rendere quelle operazioni asincrone in primo luogo. Se le operazioni non devono essere asincrone, quindi renderle sincrone per iniziare. Se hanno bisogno di essere effettivamente asincroni, non è necessario attendere in modo sincrono che finiscano. – Servy

+0

Perché questo viola l'SRP? – usr

+0

@Servy Capisco cosa intendi. Quindi ho davvero bisogno di dare il via a tutti i compiti e poi avere una funzione di attesa che dopo inizia a scoppiare i risultati. – Beastwood

risposta

5

ContinueWith è un odore di codice dal await disponibile. await è fondamentalmente un bel modo di allegare una continuazione.

Non vedo alcun problema strutturale con la prima versione del codice. Probabilmente è opportuno:

  • sostituire tutte le chiamate con Wait/Resultawait
  • cancellare Task.Run usages
  • sostituire WaitAll con await WhenAll
  • sostituire ContinueWith con un nuovo metodo asincrono e attendono

Questo dovrebbe ripulire il caos e risolvere i problemi di efficienza.

Se non hai bisogno di parallelismo puoi anche fare tutto in sincrono.

Problemi correlati