TPL и обработка на изключения

Всичко, има много въпроси по горната тема, но вярвам, че това е достатъчно различно, за да оправдае нов въпрос. Имам следното Task и продължение за справяне с различни задачи Status; TaskStatus.RanToCompletion, TaskStatus.Canceled и разбира се AggregateException през TaskStatus.Faulted. Кодът изглежда така

Task<bool> asyncTask = Task.Factory.StartNew<bool>(() =>
    asyncMethod(uiScheduler, token, someBoolean), token);

asyncTask.ContinueWith(task =>
{
    // Check task status.
    switch (task.Status)
    {
        // Handle any exceptions to prevent UnobservedTaskException.             
        case TaskStatus.RanToCompletion:
            if (asyncTask.Result)
            {
                // Do stuff...
            }
            break;
        case TaskStatus.Faulted:
            if (task.Exception != null)
                mainForm.progressRightLabelText = task.Exception.InnerException.Message;
            else
                mainForm.progressRightLabelText = "Operation failed!";
        default:
            break;
    }
}

Всичко това работи добре, но се притеснявам дали го правя правилно или не, тъй като има възможност AggregateException да бъде хвърлено от продължението - какво тогава?

Не искам да Wait на моя asyncTask, нито продължението, тъй като това ще блокира връщането към нишката на потребителския интерфейс. За да уловя всякакви изключения, хвърлени от рамките на продължение, не може да означава, че трябва да направя нещо подобно със сигурност

Task parentTask = Task.Factory.startNew(() => 
    {
        Task<bool> asyncTask = Task.Factory.StartNew<bool>(() =>
            asyncMethod(uiScheduler, token, someBoolean), token);

        Task continueTask = asyncTask.ContinueWith(task =>
            {
                // My continuation stuff...   
            }

        try
        {
            continueTask.Wait();
        }
        catch(AggregateException aggEx)
        { 
            // Some handling here...
        }
    });

това изобщо би ли проработило? Каква е най-добрата практика тук?

Както винаги, благодаря за отделеното време.


person MoonKnight    schedule 27.03.2012    source източник
comment
Виждал съм задачи, които се изпълняват до завършване, когато всъщност хвърлят AggregateException. Този вид обработка на грешки не работи. Защо просто не използвате опит/улов?   -  person Louis Kottmann    schedule 27.03.2012
comment
Искате да кажете в метода, който се извиква във фоновата нишка, или в действителния метод за делегиране на продължение?   -  person MoonKnight    schedule 27.03.2012


Отговори (2)


Вие можете да използвате традиционен опит/улавяне в рамките на вашите делегати, които наблюдават за AggregateException, или можете да свържете верижно определени продължения, които ще се изпълняват само ако антецедентът е с грешка, като използвате опцията TaskContinuationOptions.OnlyOnFaulted. Последният подход позволява да се дефинират много чисти работни потоци на задачите. Например:

Task myRootTask = ....;

myRootTask.ContinueWith(rootAntecdent =>
{
    // this will only be executed if the antecedent completed successfully, no need to check for faults
},
TaskContinuationOptions.OnlyOnRanToCompletion);

myRootTask.ContinueWith(rootAntecedent =>
{
    // this will only be executed if the antecedent faulted, observe exception and handle accordingly
},
TaskContinuationOptions.OnlyOnFaulted);
person Drew Marsh    schedule 27.03.2012

Msdn има доста добре написано „Как да“ по темата: тук

Ще забележите, че те просто използват try/catch(AggregateException) блок, след което филтрират изключението, което знаят как да обработват в ae.Handle(lambda) и спират приложението, ако има останали, които не могат да се обработят.

person Louis Kottmann    schedule 27.03.2012
comment
Запознат съм с примери като тези, предоставени от вашата връзка, и нямам проблем с обработката на eception по този начин. Проблемът ми е как да се справя с изключения, хвърлени от продължения, без да ограждам целия делегат за продължение с try catch, тогава отново това може да е единственият начин. Искам да знам най-добрите практики за код от реалния свят, а не най-добрите практики за кодове за играчки на Microsoft. наздраве - person MoonKnight; 27.03.2012
comment
OP иска да знае как да направи това, без да използва Wait. Всички примери чакат задачата. Опитайте това [msdn.microsoft.com/en-us/library/dd997415. aspx] връзка. - person Jordan Morris; 05.11.2013