Task 和 async await 需要指导

Guidance needed with Task and async await

在浏览了很多文章和视频之后,我仍然遇到异步问题 programming.I 我正在处理一个项目,在该项目中,我在服务层中将所有方法创建为异步。所有 return Task <T>Task(我确保不会 return 作废)。 现在到这个问题。我的 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 中我也在调用一个异步方法。

如何实现以及最佳做法是什么?

我相信您遇到了 here 所述的线程安全问题。如果是这样,您需要确保对于到达 EF 的每个 'awaitable',它都使用自己的 DbContext 实例。

因此,请确保您没有使用 DbContext 单例;如果可以的话,在你去的时候实例化一个新的,或者像他在 link 中那样使用容器变得棘手(容器是你的朋友)

也许您应该在编写异步方法时使用此指南

指南:

  1. 按照编写常规方法的正常方式编写方法,然后将其转换为异步方法。

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

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

      int resultValue = await ExampleMethodAsync();
    

注意:await只能用在async关键字修饰的async方法中。

  1. 在异步方法中使用正确的 return 类型之一以获得结果

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

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

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

    注:

    1. 您必须调整您的异步方法 returning。 returned 的对象必须与异步方法
    2. 的类型 Task<T> 相匹配
    3. 如果异步方法不使用等待运算符来标记挂起点,则该方法 尽管有 async 修饰符,但仍像同步方法一样执行。编译器发出一个 此类方法的警告。

下面是转为异步方法的典型方法

例子

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

希望对您有所帮助?