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

Использование задач с условными продолжениями

Я немного смущен тем, как использовать Задачи с условными продолжениями.

Если у меня есть задача, а затем я хочу продолжить выполнение задач, которые обрабатывают успех и ошибку, а затем дождаться завершения.

void FunctionThrows() {throw new Exception("faulted");}

static void MyTest()
{

    var taskThrows = Task.Factory.StartNew(() => FunctionThrows());

    var onSuccess = taskThrows.ContinueWith(
                          prev => Console.WriteLine("success"), 
                          TaskContinuationOptions.OnlyOnRanToCompleted);

    var onError = taskThrows.ContinueWith(
                          prev => Console.WriteLine(prev.Exception),
                          TaskContinuationOptions.OnlyOnFaulted);

    //so far, so good



    //this throws because onSuccess was cancelled before it was started
    Task.WaitAll(onSuccess, onError);
}

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

  //for example
  var task1 = Task.Factory.StartNew(() => ...)
  var task1Error = task1.ContinueWith(  //on faulted
  var task2  = task1.ContinueWith(      //on success
  var task2Error = task2.ContinueWith(  //on faulted
  var task3 = task2.ContinueWith(       //on success
  //etc

Вызов WaitAll для этих неизменно бросает, потому что некоторые из продолжений будут отменены из-за TaskContinuationOptions и вызывают Wait на отмененных задачах. Как мне присоединиться к ним, не получив "Отменить задачу"? "

4b9b3361

Ответ 1

Я думаю, что ваша основная проблема заключается в том, что вы сообщаете этим двум задачам "Подождите" своим вызовом

Task.WaitAll(onSuccess, onError);

Продолжения onSuccess и onError автоматически настраиваются для вас и будут выполняться после завершения антецедентной задачи.

Если вы просто замените Task.WaitAll(...) на taskThrows.Start();, я верю, что вы получите желаемый результат.

Вот несколько примеров, которые я собрал:

class Program
{
    static int DivideBy(int divisor) 
    { 
      Thread.Sleep(2000);
      return 10 / divisor; 
    }

    static void Main(string[] args)
    {
        const int value = 0;

        var exceptionTask = new Task<int>(() => DivideBy(value));

        exceptionTask.ContinueWith(result => Console.WriteLine("Faulted ..."), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.AttachedToParent);
        exceptionTask.ContinueWith(result => Console.WriteLine("Success ..."), TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.AttachedToParent);

        exceptionTask.Start();

        try
        {
            exceptionTask.Wait();
        }
        catch (AggregateException ex)
        {
            Console.WriteLine("Exception: {0}", ex.InnerException.Message);
        }

        Console.WriteLine("Press <Enter> to continue ...");
        Console.ReadLine();
    }
}

Ответ 2

Разве это не нормально?

Глядя на документацию MSDN, вы делаете это хорошо, и логика, которую вы реализуете, звучит. Единственное, чего вам не хватает, это обернуть вызов WaitAll в обертке AggregateException следующим образом:

// Exceptions thrown by tasks will be propagated to the main thread
// while it waits for the tasks. The actual exceptions will be wrapped in AggregateException.
try
{
    // Wait for all the tasks to finish.
    Task.WaitAll(tasks);

    // We should never get to this point
    Console.WriteLine("WaitAll() has not thrown exceptions. THIS WAS NOT EXPECTED.");
}
catch (AggregateException e)
{
    Console.WriteLine("\nThe following exceptions have been thrown by WaitAll(): (THIS WAS EXPECTED)");
    for (int j = 0; j < e.InnerExceptions.Count; j++)
    {
        Console.WriteLine("\n-------------------------------------------------\n{0}", e.InnerExceptions[j].ToString());
    }
}

Вы можете прочитать больше здесь: http://msdn.microsoft.com/en-us/library/dd270695.aspx

В сущности, улавливание AggregatedException дает вам то же самое, что и завершение WaitAll. Это сборник всех исключений, возвращаемых из ваших задач.

Ответ 3

Используйте Task.WaitAny(onSuccess, onError);