【问题标题】:.Net Async ContinueWith VS Embedding Tasks in Task.Net Async ContinueWith VS 在任务中嵌入任务
【发布时间】:2015-09-24 23:54:26
【问题描述】:

只是想知道异步的最佳方法。起初我的代码看起来像这样(示例被简化)。

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。我做了一些研究(又名查看了其他 stackoverflow 帖子),我在 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

我想知道这些方法中的哪一种会被认为是“正确的方法”?

【问题讨论】:

  • 您不断地同步阻塞任务,这违背了使这些操作首先异步的目的。如果操作不需要是异步的,那么让它们同步开始。如果它们实际上需要异步,那么您不需要同步等待它们完成。
  • 为什么这违反了 SRP?
  • @Servy 我明白你的意思了。所以我真的需要启动所有任务,然后有一个 waitall 函数,然后开始分解结果。
  • @usr 我认为既然 FindSubscriptions() 方法正在查找订阅,因此它也不应该负责分配发送通知调用。但我可能想多了!
  • @Beastwood 不,那仍然是同步阻塞的。

标签: c# .net asynchronous async-await task


【解决方案1】:

ContinueWith 是一种代码气味,因为await 可用。 await 基本上是一种附加延续的好方法。

我认为您的代码的第一个版本没有结构性问题。您可能应该:

  • 将所有Wait/Result 调用替换为await
  • 删除 Task.Run 用法
  • 将 WaitAll 替换为 await WhenAll
  • 用新的异步方法替换 ContinueWith 并等待

这应该会清理混乱并解决效率问题。

如果您不需要并行性,您也可以使一切同步。

【讨论】:

    猜你喜欢
    • 2018-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-29
    • 2017-04-21
    • 2017-12-03
    相关资源
    最近更新 更多