问题
I am using the new async await features to upgrade from backgroundworker in C#. In the following code I am trying to replicate the execution of multiple tasks with ContinueWith method.
Task t1 = new Task
(
() =>
{
Thread.Sleep(10000);
// make the Task throw an exception
MessageBox.Show("This is T1");
}
);
Task t2 = t1.ContinueWith
(
(predecessorTask) =>
{
if (predecessorTask.Exception != null)
{
MessageBox.Show("Predecessor Exception within Continuation");
return;
}
Thread.Sleep(1000);
MessageBox.Show("This is Continuation");
},
TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.OnlyOnRanToCompletion
);
t1.Start();
try
{
t1.Wait(); <------ Comment
t2.Wait(); <------ Comment
}
catch (AggregateException ex)
{
MessageBox.Show(ex.InnerException.Message);
}
My question is when I comment t1.wait and t2.wait Tasks are not blocking UI. However when I uncomment t1.wait and t2.wait UI blocks until thread is completed. The desired behavior is to catch errors in try/catch block without blocking UI. What Am I missing?
回答1:
If this is running within a UI event handler, you can add the async
modifer to the method signature and change t1.Wait()
to await t1
. This will return control to the UI thread, and when the Thread.Sleep has completed, the continuation will execute and any exceptions will be caught.
回答2:
When you use Task.Wait()
, you are basically saying "wait here my task to complete". That's why you are blocking the thread. A good way to handle exception in tasks is using the Task.ContinueWith
overload and pass OnlyOnFaulted
as TaskContinuationOption
which would look like:
Task yourTask = new Task {...};
yourTask.ContinueWith( t=> { /*handle expected exceptions*/ }, TaskContinuationOptions.OnlyOnFaulted );
回答3:
If you're going to use the Task-based Asynchronous Pattern, then you should use the recommended guidelines. I have an MSDN article describing many of them.
In particular:
- Use
Task.Run
instead of theTask
constructor withTask.Start
. - Use
await
instead ofContinueWith
. - Do not use
AttachedToParent
.
If you apply these changes, your code will then look like this:
try
{
await Task.Run(() =>
{
Thread.Sleep(10000);
// make the Task throw an exception
MessageBox.Show("This is T1");
});
await Task.Run(() =>
{
Thread.Sleep(1000);
MessageBox.Show("This is Continuation");
});
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
来源:https://stackoverflow.com/questions/19206369/async-wait-block-main-ui