我有一个Windows服务,它根据计划运行各种作业。确定要运行的作业后,会将一个计划对象列表发送到迭代列表并运行每个作业的方法。问题是由于外部数据库调用,某些作业最多可能需要10分钟才能运行。
我的目标是没有一个工作阻止其他队列,基本上一次有多个运行。我认为使用async和await可以解决这个问题,但我以前从未使用过这些。
当前代码:
public static bool Load(List<Schedule> 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<bool> LoadAsync(List<Schedule> scheduleList)
{
foreach (Schedule schedule in scheduleList)
{
bool result = await LoadAsync((int)schedule.JobId, schedule.ScheduleId);
}
return true;
}
public async static Task<bool> LoadAsync(int scheduleId)
{
// make database and other external resource calls
// some jobs run for up to 10 minutes
return true;
}
问题是第一个LoadAsync在将控制权交还给循环之前等待作业完成,而不是允许所有作业启动。
我有两个问题:
答案 0 :(得分:26)
高级别 - async /等待最佳选择,还是应该使用不同的方法?
async-await
非常适合您尝试执行的操作,即同时卸载多个IO绑定任务。
需要更新哪些内容以允许循环在不阻塞的情况下启动所有作业,但是在完成所有作业之前不允许函数返回?
您的循环目前正在等待,因为您await
每次调用LoadAsync
。你想要的是同时执行它们,而不是等待所有它们完成Task.WhenAll
:
public async static Task<bool> LoadAsync(List<Schedule> scheduleList)
{
var scheduleTaskList = scheduleList.Select(schedule =>
LoadAsync((int)schedule.JobId, schedule.ScheduleId)).ToList();
await Task.WhenAll(scheduleTaskList);
return true;
}
答案 1 :(得分:4)
对于扇出并行异步调用,您希望触发任务以启动它们运行,但随后将它们作为异步未来或承诺值处理。完成所有操作后,您可以在最后同步/等待它们。
最简单的方法是将你的for循环变成这样的东西:
List<Task<bool>> jobs = new List<Task<bool>>();
foreach (var schedule in scheduleList)
{
Task<bool> 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);
答案 2 :(得分:-1)
我建议使用Parallel.ForEach。它不是异步的,并行运行每个迭代。正是你需要的。
public static bool Load(IEnumerable<Schedule> 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;
}