Ждите выполнения задачи так же, как и задачи.Результат?
в настоящее время я читаю "параллелизм в C# Cookbook" Стивена Клири, и я заметил следующую технику:
var completedTask = await Task.WhenAny(downloadTask, timeoutTask);
if (completedTask == timeoutTask)
return null;
return await downloadTask;
downloadTask - это вызов httpclient.GetStringAsync, и timeoutTask задача выполняется.Задержка.
в случае, если это не тайм-аут, то downloadTask уже завершена. Почему необходимо сделать второе ожидание вместо возврата задачи загрузки.Результат, учитывая, что задача уже закончили?
2 ответа:
уже есть несколько хороших ответов/комментариев, но просто, чтобы поучаствовать в обсуждении...
есть две причины, почему я предпочитаю
awaitoverResult(или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и его внутренних исключений в любом случае, чтобы добраться до причины ошибки.