Подтвердить что ты не робот

Что произойдет, если я не жду задания?

Рассмотрим следующий пример:

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, но это не должно вызывать никаких проблем?

4b9b3361

Ответ 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);
 }

Более подробную информацию можно найти здесь и здесь.