В соответствии с предоставленной вам реализацией, вызов Task.WaitAll
блокирует вызывающий поток до тех пор, пока все задачи не будут завершены. Он только перейдет к следующей строке и выполнит проверку Exists
после того, как это произошло. Если вы удалите Task.WaitAll
, то проверка Exists
приведет к тому, что вызывающий поток будет блокировать каждую задачу по порядку; то есть сначала блокируется на tasks[0]
; если он возвращает false, то он блокируется на tasks[1]
, затем tasks[2]
и так далее. Это нежелательно, поскольку не позволяет вашему методу завершиться досрочно, если задачи завершаются не по порядку.
Если вам нужно только подождать, пока какая-либо задача не вернет значение true, тогда вы можете использовать Task.WhenAny
. Это заставит ваш асинхронный метод возобновить работу, как только любая задача будет завершена. Затем вы можете проверить, соответствует ли оно значению true, и сразу же вернуть результат; в противном случае вы продолжаете повторять процесс для оставшегося набора задач, пока не останется ни одного.
Если ваш код выполнялся как приложение (WPF, WinForms, Console), то оставшиеся задачи продолжали бы выполняться в пуле потоков до завершения, пока приложение не будет закрыто. Потоки пула потоков являются фоновыми потоками, поэтому они не будут поддерживать процесс в активном состоянии, если все потоки переднего плана были прерваны (например, потому что все окна были закрыты).
Поскольку вы запускаете веб-приложение, вы рискуете перезапустить пул приложений до того, как задачи будут завершены. Неожиданные задачи запускаются и забываются и поэтому не отслеживаются средой выполнения. Чтобы этого не происходило, вы можете зарегистрировать их во время выполнения с помощью метода HostingEnvironment.QueueBackgroundWorkItem
, как предлагается в комментариях.
[HttpPost]
public async Task<IActionResult> PostCall()
{
var tasks = Enumerable
.Range(0, 10)
.Select(Manager.SomeMethodAsync)
.ToList();
foreach (var task in tasks)
HostingEnvironment.QueueBackgroundWorkItem(_ => task);
while (tasks.Any())
{
var readyTask = await Task.WhenAny(tasks);
tasks.Remove(readyTask);
if (await readyTask)
return new ObjectResult("At least one task returned true");
}
return new ObjectResult("No tasks returned true");
}