Task和async所需的指导等待

时间:2018-06-01 09:25:27

标签: c# entity-framework async-await task-parallel-library

经过大量文章和视频后,我仍然遇到异步编程问题。我正在开发一个项目,在服务层我创建了所有方法async。所有返回Task <T>Task(我确保不返回void)。 现在问题。我的Api调用异步方法,内部调用其他异步方法,甚至可以调用其他异步方法。所以每次遇到异步方法时我都会等待。 我认为,这种方法的缺点是因为每次遇到异步时我都在等待结果需要花费很多时间。例如:

public async Task<xyz> DoMainTask(int ActionId, int ItemId, int UserId)
{
   await DoTask1(ActionId,ItemId,UserId);  3 sec
   await DoTask2(ActionId,ItemId,UserId);  3 sec
   await DoTask3(ActionId,ItemId,UserId);  3 sec
}

所以我不想等待9秒,因为这里的所有任务都是相互独立的。 我想做点什么:

public async Task<xyz> DoMainTask(int ActionId, int ItemId, int UserId)
{
   List<Task> lst = new List<Task>();
   t1= DoTask1(ActionId,ItemId,UserId);  
   lst.Add(t1);

   t2 = DoTask2(ActionId,ItemId,UserId);
   lst.Add(t2);

   t3 = DoTask3(ActionId,ItemId,UserId);
   lst.Add(t3);

   await Task.WhenAll(lst);

   // do some work
   return xyz;
}

这可能需要5-6秒左右。我该怎么做呢? 每当我尝试使用第二种方法时都会出错:

在上一次异步操作完成之前,在此上下文中启动了第二个操作

DoTask1定义为:

  public async Task DoTask1 (int ActionId, int ItemId, int UserId)
    {
        try
        {
            DailyActivityPoint dailyActivityPoint = new DailyActivityPoint()
            {
                ActionId = ActionId,
                CreatedDate = DateTime.Now,
                ItemId = ItemId,
                UserId = UserId,
                PointsAccumulated = await GetPointsAwardedForAction(ActionId)
            };

            _entities.DailyActivityPoints.Add(dailyActivityPoint);
            await _entities.SaveChangesAsync();
        }
        catch (Exception ex)
        {

        }
    }

在DoTask1中我也在调用异步方法。

如何做到这一点以及最佳做法是什么?

2 个答案:

答案 0 :(得分:1)

我相信您遇到了here所描述的线程安全问题。如果是这样,那么您需要确保每个等待的人都能等待。到达EF它正在使用自己的DbContext实例。

所以,请确保您没有使用DbContext单身人士;如果你可以或者像链接中那样容易使用容器(容器是你的朋友),你可以实例化一个新的

答案 1 :(得分:0)

也许你应该在编写异步方法时使用这个指南

准则:

  1. 以常规方法编写方法,然后将其转换为异步方法。

  2. 在方法声明中使用async关键字。

    public async Task<int> ExampleMethodAsync()  
    {  
        // . . . .  
    } 
    
  3. 在调用异步流程/方法的代码中使用await关键字。

      int resultValue = await ExampleMethodAsync();
    
  4. 注意: await只能用于async关键字修改的异步方法。

    1. 在async方法中使用正确的返回类型之一以获得结果

      return types for an async method need to be one of the following:
      
      • 如果您的方法有一个返回语句,其中操作数的类型为TResult。
      • 如果您的方法没有return语句或者没有操作数的return语句,则执行任务。
      • 如果您正在编写异步事件处理程序,则无效。
    2. 在调用方法名称的末尾添加“Async”后缀。这不是必需的,但需要考虑 在C#中编写异步方法的约定。

      public async Task<int> ExampleCallingMethodAsync()  
      {  
          // . . . .  
      }
      
    3. 在async方法代码中至少包含一个await表达式。 在await表达式中暂停异步方法不会 构成该方法的退出,最后块不运行。

      public async Task<int> ExampleMethodAsync()  
      {  
       //some code
       string pageContents = await client.GetStringAsync(uri);   
       //some more code
       return pageContents.Length;
      }
      

      注意:

      1. 您必须调整异步方法返回的内容。返回的对象必须与异步方法的类型Task<T>匹配
      2. 如果异步方法不使用await运算符来标记暂停点,则该方法 尽管是异步修饰符,但作为同步方法执行。编译器发出一个 警告这些方法。
    4. 以下是转换为异步方法的典型方法

      示例

          private void WebPage(string someURI) 
       { 
          WebClient webClient = new WebClient(); 
          string pageContent = webClient.DownloadString(someURI);
          Console.WriteLine(pageContent);
       }
      

      更改为:

         private async void WebPageAsync(string someURI)
       { 
        WebClient webClient = new WebClient();
        string pageContent = await webClient.DownloadStringTaskAsync(someURI); 
        Console.WriteLine(pageContent); 
       }
      

      我希望这有用吗?