Ждите выполнения задачи так же, как и задачи.Результат?
в настоящее время я читаю "параллелизм в C# Cookbook" Стивена Клири, и я заметил следующую технику:
var completedTask = await Task.WhenAny(downloadTask, timeoutTask);
if (completedTask == timeoutTask)
return null;
return await downloadTask;
downloadTask - это вызов httpclient.GetStringAsync, и timeoutTask задача выполняется.Задержка.
в случае, если это не тайм-аут, то downloadTask уже завершена. Почему необходимо сделать второе ожидание вместо возврата задачи загрузки.Результат, учитывая, что задача уже закончили?
2 ответа:
уже есть несколько хороших ответов/комментариев, но просто, чтобы поучаствовать в обсуждении...
есть две причины, почему я предпочитаю
await
overResult
(илиWait
). Во-первых, что обработка ошибок отличается;await
не переносит исключение вAggregateException
. В идеале, асинхронный код никогда не должен иметь дело сAggregateException
вообще, если это специально хочет для.вторая причина-немного более тонкая. Как я описываю в своем блоге (и в книге),
Result
/Wait
может привести к взаимоблокировкам и может вызвать еще более тонкие тупики при использовании вasync
метод. Итак, когда я читаю код и вижуResult
илиWait
, это немедленное предупреждение. ЭлементResult
/Wait
правильно только если вы абсолютно точно что задача уже завершена. Это не только трудно увидеть с первого взгляда (в реальном коде), но и более хрупко для кода изменения.это не значит, что
Result
/Wait
должны никогда использоваться. Я следую этим рекомендациям в своем собственном коде:
- асинхронный код в приложении можно использовать только
await
.- асинхронный код утилиты (в библиотеке) можно иногда использовать
Result
/Wait
если код действительно требует этого. Такое использование, вероятно, должно иметь комментарии.- параллельно код задачи может использовать
Result
иWait
.обратите внимание, что (1) на сегодняшний день является общим случаем, поэтому моя тенденция использовать
await
везде и рассматривать другие случаи как исключения из общего правила.
это имеет смысл, если
timeoutTask
продуктTask.Delay
, которая, я считаю, что это в книге.
Task.WhenAny
возвращаетTask<Task>
, где внутренняя задача является одним из тех, которые вы передали в качестве аргументов. Это можно было бы переписать так:Task<Task> anyTask = Task.WhenAny(downloadTask, timeoutTask); await anyTask; if (anyTask.Result == timeoutTask) return null; return downloadTask.Result;
в любом случае, потому что
downloadTask
уже завершена, есть очень незначительная разница междуreturn await downloadTask
иreturn downloadTask.Result
. Дело в том, что последний будет бросатьAggregateException
который обертывает любое исходное исключение, как указано @Кириллшленский в комментариях. Первый просто повторно бросит исходное исключение.в любом случае, где бы вы ни обрабатывали исключения, вы должны проверить
AggregateException
и его внутренних исключений в любом случае, чтобы добраться до причины ошибки.