首页 > 解决方案 > 异步等待过度使用

问题描述

我有一个关于过度使用async-await运算符的问题。
我有一个Zoo实例列表,我需要将每个实例的每个成员分别插入Zoo到数据库中。这是Zoo类定义:

class Zoo
{
public Dog Dog { get; set; }
public Cat Cat { get; set; }
public Bear Bear { get; set; }
}

下面提供插入方法Zoo。每个实例Zoo及其成员都应该在插入之前进行验证或转换,所以我处理它们Parallel.For

public void Save(List<Zoo> zoos)
{
 Parallel.For(0, zoos.Count, new ParallelOptions { MaxDegreeOfParallelism = 4 }, async i =>
  {
  ...
  Task saveDog = Task.Run(async () => await InsertDogAsync(zoos[i], string connectionString));
  Task saveCat = Task.Run(async () => await InsertCatAsync(zoos[i], string connectionString));
  Task saveBear = Task.Run(async () => await InsertBearAsync(zoos[i], string connectionString));
  await Task.WhenAll(new Task[] { saveDog, saveCat, saveBear });
  ...
  });
}

我使用方法将动物插入数据库async。例如这里是Dog

private static async Task InsertDogAsync(Zoo zoo, string connectionString)
{
 using SqlConnection connection = new SqlConnection(connectionString);
 await connection.OpenAsync();
 ...
 using SqlCommand insertCommand = new SqlCommand("sp_insertDog", connection); // stored procedure
 ...
 await insertCommand.ExecuteNonQueryAsync();
}

我的问题如下:是否过度使用async-await运算符?正如我所意识到的,每个await操作员在完成之前都会释放线程,但是方法是在并行任务中调用的,因此线程用于不同的任务。也许从lambda中删除一些async-await(例如)更容易接受?Task.Run

标签: c#.netsql-serverasync-awaitparallel.for

解决方案


这不是await过度使用的情况,而是await滥用的情况。该Parallel.ForEach方法不是异步友好的,并且使用async委托提供给它是一个错误:它没有做你期望它做的事情。如果要同时启动多个异步操作,同时控制并发级别,正确​​使用的 API 就是Parallel.ForEachAsync方法。此方法将在即将推出的 .NET 6 中引入,因此目前您只能使用自制解决方案,例如在这个问题中找到的解决方案。


推荐阅读