任务和异步所需的指导等待[重复]

问题描述 投票:1回答:2

这个问题在这里已有答案:

经过大量文章和视频后,我仍然遇到异步编程问题。我正在开发一个项目,在服务层我已经创建了所有方法async。所有返回Task <T>Task(我确保不返回无效)。现在问题。我的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里面我也在调用异步方法。

怎么做,什么是最佳做法?

c# entity-framework async-await task-parallel-library
2个回答
1
投票

我相信你遇到了here描述的线程安全问题。如果是这样,你需要确保对于进入EF的每个'等待',它使用自己的DbContext实例。

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


0
投票

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

指南:

  1. 以常规方法编写常规方法编写方法,然后将其转换为异步方法。
  2. 在方法声明中使用async关键字。 public async Task<int> ExampleMethodAsync() { // . . . . }
  3. 在调用异步进程/方法的代码中使用await关键字。 int resultValue = await ExampleMethodAsync();

注意:await只能在async关键字修改的异步方法中使用。

  1. 在async方法中使用正确的返回类型之一以获得结果 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. 在async方法代码中包含至少一个await表达式。在await表达式中暂停异步方法不构成对方法的退出,最后块不会运行。 public async Task<int> ExampleMethodAsync() { //some code string pageContents = await client.GetStringAsync(uri); //some more code return pageContents.Length; } 注意: 您必须调整异步方法返回的内容。返回的对象必须与异步方法的类型Task<T>匹配 如果异步方法不使用await运算符来标记挂起点,则该方法将作为同步方法执行,尽管存在异步修饰符。编译器会为此类方法发出警告。

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

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

我希望这可以帮到你?

© www.soinside.com 2019 - 2024. All rights reserved.