异步并等待For循环

我有一个Windows服务,根据计划运行各种作业。 确定要运行的作业后,会将一个计划对象列表发送到迭代列表并运行每个作业的方法。 问题是由于外部数据库调用,某些作业最多可能需要10分钟才能运行。

我的目标是没有一个工作阻止其他队列,基本上一次有多个运行。 我认为使用async和await可以解决这个问题,但我以前从未使用过这些。

现行代码:

public static bool Load(List scheduleList) { foreach (Schedule schedule in scheduleList) { Load(schedule.ScheduleId); } return true; } public static bool Load(int scheduleId) { // make database and other external resource calls // some jobs run for up to 10 minutes return true; } 

我尝试更新到这段代码:

 public async static Task LoadAsync(List scheduleList) { foreach (Schedule schedule in scheduleList) { bool result = await LoadAsync((int)schedule.JobId, schedule.ScheduleId); } return true; } public async static Task LoadAsync(int scheduleId) { // make database and other external resource calls // some jobs run for up to 10 minutes return true; } 

问题是第一个LoadAsync在将控制权交还给循环之前等待作业完成,而不是允许所有作业启动。

我有两个问题:

  1. 高水平 – aysnc /等待是最好的选择,还是我应该采用不同的方法?
  2. 需要更新什么才能让循环在不阻塞的情况下启动所有作业,但是在所有作业完成之前不允许函数返回?

高级别 – 是异步/等待最佳选择,还是应该使用不同的方法?

async-await非常适合您尝试执行的操作,它可以同时卸载多个IO绑定任务。

需要更新什么才能让循环在不阻塞的情况下启动所有作业,但是在所有作业完成之前不允许函数返回?

您的循环当前正在等待,因为您await每次调用LoadAsync 。 你想要的是同时执行它们,而不是等待所有它们完成使用Task.WhenAll

 public async static Task LoadAsync(List scheduleList) { var scheduleTaskList = scheduleList.Select(schedule => LoadAsync((int)schedule.JobId, schedule.ScheduleId)).ToList(); await Task.WhenAll(scheduleTaskList); return true; } 

对于扇出并行异步调用,您希望触发Task以启动它们运行,但随后将它们作为异步future或promise值处理。 完成所有操作后,您可以在最后同步/等待它们。

最简单的方法是将你的for循环变成这样的东西:

 List> jobs = new List>(); foreach (var schedule in scheduleList) { Task job = LoadAsync((int) schedule.JobId, schedule.ScheduleId); // Start each job jobs.Add(job); } bool[] finishedJobStatuses = await Task.WhenAll(jobs); // Wait for all jobs to finish running bool allOk = Array.TrueForAll(finishedJobStatuses, p => p); 

我建议使用Parallel.ForEach。 它不是异步的,并行运行每个迭代。 正是你需要的。

 public static bool Load(IEnumerable scheduleList) { // set the number of threads you need // you can also set CancellationToken in the options var options = new ParallelOptions { MaxDegreeOfParallelism = 5 }; Parallel.ForEach(scheduleList, options, async schedule => { await Load(schedule.ScheduleId); }); return true; }