В настоящее время я читаю « Поваренную книгу о параллелизме в C # » Стивена Клири и заметил следующий прием:
var completedTask = await Task.WhenAny(downloadTask, timeoutTask);
if (completedTask == timeoutTask)
return null;
return await downloadTask;
downloadTask
является вызовом httpclient.GetStringAsync
и timeoutTask
выполняется Task.Delay
.
В том случае, если он не истек, значит, downloadTask
он уже завершен. Почему необходимо выполнить второе ожидание вместо возврата downloadTask.Result
, если задача уже выполнена?
c#
asynchronous
async-await
task
julio.g
источник
источник
downloadTask
иtimeoutTask
? Что они делают?AggregateException
сResult
первым исключением vs черезExceptionDispatchInfo
withawait
). Более подробно обсуждается в статье Стивена Туба «Обработка исключений в задачах в .NET 4.5»: blogs.msdn.com/b/pfxteam/archive/2011/09/28/… )Ответы:
Здесь уже есть несколько хороших ответов / комментариев, но просто чтобы поддержать ...
Есть две причины , почему я предпочитаю
await
болееResult
(илиWait
). Во-первых, другая обработка ошибок;await
не переносит исключение в файлAggregateException
. В идеале с асинхронным кодом вообще не должно приходиться иметь делоAggregateException
, если только он этого не хочет .Вторая причина более тонкая. Как я описываю в своем блоге (и в книге),
Result
/Wait
может вызывать взаимоблокировки , а при использовании вasync
методе может вызывать еще более тонкие взаимоблокировки . Итак, когда я читаю код и вижуResult
илиWait
, это немедленное предупреждение.Result
/Wait
Является единственно правильным , если вы абсолютно уверены в том , что задача уже выполнена. Это не только трудно увидеть с первого взгляда (в реальном коде), но и более уязвимо для изменений кода.Это не означает , что
Result
/Wait
не должны никогда быть использованы. Я следую этим рекомендациям в собственном коде:await
.Result
/,Wait
если код действительно требует этого. Такое использование, вероятно, должно иметь комментарии.Result
иWait
.Обратите внимание, что (1) - это, безусловно, общий случай, отсюда моя тенденция использовать
await
везде и рассматривать другие случаи как исключения из общего правила.источник
await
мешаетAggregateException
обертка.AggregateException
был разработан для параллельного программирования, а не для асинхронного программирования.Wait
было присоединение к экземплярам динамического параллелизма задачTask
. Использование его для ожидания асинхронныхTask
экземпляров опасно. Microsoft рассматривала возможность введения нового типа «Promise», но предпочла использовать существующийTask
; компромисс повторного использования существующегоTask
типа для асинхронных задач заключается в том, что в итоге вы получаете несколько API, которые просто не должны использоваться в асинхронном коде.Это имеет смысл, если
timeoutTask
это продукт, оTask.Delay
котором я верю в книге.Task.WhenAny
возвращаетTask<Task>
, где внутренняя задача - одна из тех, которые вы передали в качестве аргументов. Это можно было бы переписать так:В любом случае, поскольку
downloadTask
он уже завершен, разница междуreturn await downloadTask
и очень незначительнаreturn downloadTask.Result
. Дело в том, что последний будетAggregateException
вызывать любое исходное исключение, как указано @KirillShlenskiy в комментариях. Первый просто повторно вызовет исходное исключение.В любом случае, где бы вы ни обрабатывали исключения, вы
AggregateException
все равно должны проверять наличие и его внутренние исключения, чтобы выяснить причину ошибки.источник