C # async CTP - Как пометить асинхронную задачу как отмененную, не выбрасывая TaskCanceledException? - PullRequest
6 голосов
/ 12 августа 2011

У меня короткая асинхронная задача, которую часто нужно отменять после ее запуска. Класс «Task» имеет индикатор IsCanceled, который, я думаю, было бы удобно использовать для указания того, что асинхронная задача была отменена без выполнения до конца, но, насколько я могу судить, единственный способ пометить асинхронную задачу как отмененную бросить TaskCanceledException в асинхронную функцию. Выдача исключения регулярно, чтобы указать на ситуацию, которая происходит без исключения, идет вразрез с тем, как я понимаю, исключения следует использовать. Кто-нибудь знает лучший способ указать асинхронную задачу, которая будет отменена, когда ожидается, что она будет выполняться часто?

Моя следующая лучшая альтернатива - вернуть структуру, которая имеет собственное свойство IsCanceled:

(для краткости я проигнорировал некоторые хорошие практики кодирования и стиля)

class MightBeCanceled<T>
{
    public readonly T Value;
    public readonly bool IsCanceled;

    public MightBeCanceled(T value) { Value = value; IsCanceled = false; }
    public static MightBeCanceled<T> Canceled = new MightBeCanceled<T>(default(T), true);
    private MightBeCanceled(T value, bool isCanceled) { Value = value; IsCanceled = isCanceled; }
}

...

static async Task<MightBeCanceled<int>> Foo()
{
    if (someCancellationCondition)
        return MightBeCanceled<int>.Canceled;
    else
        return new MightBeCanceled<int>(42);
}

static async void Bar() 
{
    var mightBeCanceled = await Foo();

    if (mightBeCanceled.IsCanceled)
        ; // Take canceled action
    else
        ; // Take normal action
}

Но это кажется излишним и сложнее в использовании. Не говоря уже о том, что это создает проблемы согласованности, потому что будет два IsCanceled (один в Задаче и один в MightBeCanceled).

Ответы [ 2 ]

2 голосов
/ 22 августа 2011

Обычно цель отмены состоит в том, чтобы инициатор асинхронного действия сказал действию, что он должен прекратить обработку. Для этого вы передаете CancellationToken в асинхронный метод. Вот почему ожидание Задачи, которая устанавливает IsCancelled, выдает себя. Это означает исключительный сигнал к внешне спровоцированному действию. Отмена задачи не должна использоваться для потока управления, а только для того, чтобы асинхронное действие могло завершиться раньше, если ожидающая сторона дала понять, что она больше не хочет результата.

Если ваши асинхронные действия отменены изнутри, вы уже перегрузили концепцию, и я бы сказал, что это отражение этой разницы в отмене имеет смысл и должно быть свойством в контейнере результатов, аналогично тому, как вы его предлагали. Но вместо того, чтобы называть это MightBeCancelled<T>, может быть, что-то вроде InternallyCancellableResult<T>, чтобы отразить разницу в понятиях отмены.

2 голосов
/ 12 августа 2011

Проблема в том, что исключение не будет замечено, пока вы не решите его дождаться. Таким образом, акт вызова await означает, что вы в конечном итоге увидите исключение в какой-то момент, когда будет возвращено окончательное значение или если вы дождетесь завершения задачи. Однако, если вам все равно (это задача «забей и забудь»), исключение не является проблемой (по большей части).

Я тоже нахожу это немного странным, всегда нужно пытаться / ловить задачу для обработки агрегатных исключений. Однако, подумайте немного:

 try
 {
     var myResult = await Foo();

     // Do Success Actions Here... 
 }
 catch(AggregateException e)
 {
     e.Flatten().Handle(ex =>
       {
           if(ex is OperationCanceledException)
           {
               // Do Canceled Thing Here
               return true;
           }

           return false;
       });
 }

Это не так уж далеко. Во многом я думаю об отмене другой задачи, и как бы я это сделал? ThreadAbortException? Кажется, это не так просто, чтобы просто выдать конкретное исключение при отмене.

Это в значительной степени паттерн, который я видел в нескольких местах для того, как справляться с отменой.

...