Что произойдет, если я не жду задания?
Рассмотрим следующий пример:
var task = DoSomething()
bool ready = await DoSomethingElse();
if (!ready)
return null;
var value = await DoThirdThing(); // depends on DoSomethingElse
return value + await task;
DoSomething
выполняет очень важную работу, которая может занять некоторое время, поэтому мы сначала начинаем ее.
Тем временем мы проверяем, готовы ли мы с DoSomethingElse
и выходим раньше, если нет.
Мы называем DoThirdThing
, только если мы ready
, поскольку вселенная могла бы иначе взорваться.
Мы не можем использовать Task.WhenAll
, поскольку DoThirdThing
зависит от DoSomethingElse
, и мы также не хотим ждать DoSomething
, потому что мы хотим, по возможности, вызывать другие два метода.
Вопрос: Что происходит с task
, если мы не ready
и выходим раньше?
Будут ли какие-либо исключения, которые он выбрасывает, перебрасывают с помощью SynchronizationContext
?
Существуют ли проблемы, если task
завершается нормально, поскольку никто не потребляет его значение?
Последующее наблюдение: Есть ли опрятный способ убедиться, что task
ожидает?
Мы могли бы просто await task
, если бы мы не были ready
, однако если бы было 50 условий выхода, это было бы очень утомительно.
Может ли блок finally
использоваться для await task
и повторно выбрасывать потенциальные исключения? Если task
закончен нормально, он будет снова ожидаться в блоке finally
, но это не должно вызывать никаких проблем?
Ответы
Ответ 1
Вопрос: что происходит с задачей, если мы не готовы и рано выходим?
Ничего. Код игнорирует задачу, поэтому задача игнорируется.
Будут ли какие-либо исключения, которые он выбрасывает, повторно создаются с помощью SynchronizationContext?
Нет. Они будут (в конечном итоге) переданы на TaskScheduler.UnobservedTaskException
, а затем проигнорированы.
Существуют ли проблемы, если задача выполняется нормально, поскольку никто не потребляет ее значение?
Неа.
Последующее наблюдение: существует ли опрятный способ убедиться, что задача ожидаема?
Нет.
Может ли последний блок использоваться для ожидания задачи и повторного выброса потенциальных исключений?
Да, если ваш код действительно await
задание. Предположительно это означало бы сохранение задачи где-то.
Если задание выполнено нормально, оно будет снова ожидаться в блоке finally, но это не должно вызывать никаких проблем?
Вы можете await
выполнить задание столько раз, сколько захотите.
Мы могли бы просто ждать задания, если мы не готовы, однако если бы было 50 условий выхода, это было бы очень утомительно.
Затем рассмотрите вопрос о реструктуризации вашего кода.
Ответ 2
Последующее наблюдение: существует ли опрятный способ убедиться, что задача ожидаема?
Если вам нужен индивидуальный, более мелкозернистый, чем TaskScheduler.UnobservedTaskException
контроль над исключениями, создаваемыми задачами, которые вы не выполняете await
, для этого есть удобный инструмент: async void
.
Ваш код может выглядеть так:
static async void Observe(Task task)
{
// use try/catch here if desired so;
// otherwise, exceptions will be thrown out-of-band, i.e.
// via SyncronizationContext.Post or
// via ThreadPool.QueueUSerWorkItem (if there no sync. context)
await task;
}
// ...
var taskObserved = false;
var task = DoSomething()
try
{
bool ready = await DoSomethingElse();
if (!ready)
return null;
var value = await DoThirdThing(); // depends on DoSomethingElse
taskObserved = true;
return value + await task;
}
finally
{
if (!taskObserved)
Observe(task);
}
Более подробную информацию можно найти здесь и здесь.