Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different exception handling between Task.Run and Task.Factory.StartNew

I encountered an issue when I was using Task.Factory.StartNew and tried to capture an exception that is thrown. In my application I have a long running task that I want to encapsulate in a Task.Factory.StartNew(.., TaskCreationOptions.LongRunning);

However, the exception isn't caught when I'm using Task.Factory.StartNew. It is however working as I expect when I use Task.Run, which I thought was just a wrapper on Task.Factory.StartNew (according to for instance this MSDN article).

A working example is provided here, the difference being that the exception is written to console when using Task.Run, but not when using Factory.StartNew.

My question would be:
if I have a LongRunning task that has the possibility to throw exceptions, how should I handle them in the calling code?

private static void Main(string[] args)
{
    Task<bool> t = RunLongTask();
    t.Wait();
    Console.WriteLine(t.Result);
    Console.ReadKey();
}

private async static Task<bool> RunLongTask()
{
    try
    {
        await RunTaskAsync();
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        return false;
    }
    Console.WriteLine("success");
    return true;
}

private static Task RunTaskAsync()
{
    //return Task.Run(async () =>
    //    {
    //        throw new Exception("my exception");
    //    });
    return Task.Factory.StartNew(
        async () =>
    {
        throw new Exception("my exception");
    });

}
like image 442
default Avatar asked Feb 06 '13 13:02

default


People also ask

What is the difference between task run and task factory StartNew?

Task. Run(action) internally uses the default TaskScheduler , which means it always offloads a task to the thread pool. StartNew(action) , on the other hand, uses the scheduler of the current thread which may not use thread pool at all!

What does task factory StartNew do?

StartNew(Action<Object>, Object, CancellationToken, TaskCreationOptions, TaskScheduler) Creates and starts a task for the specified action delegate, state, cancellation token, creation options and task scheduler.

What are the tasks to be handled by exception handling?

Exceptions are propagated when you use one of the static or instance Task. Wait methods, and you handle them by enclosing the call in a try / catch statement. If a task is the parent of attached child tasks, or if you are waiting on multiple tasks, multiple exceptions could be thrown.

What is task run?

In . NET, Task. Run is used to asynchronously execute CPU-bound code. Let's say there is a method which does some CPU-bound work. Example : looping through a large array and doing some complex computation on each element of the array.


1 Answers

Your problem is that StartNew doesn't work like Task.Run with async delegates. The return type of StartNew is Task<Task> (which is convertible to Task). The "outer" Task represents the beginning of the method, and the "inner" Task represents the completion of the method (including any exceptions).

To get to the inner Task, you can use Unwrap. Or you can just use Task.Run instead of StartNew for async code. LongRunning is just an optimization hint and is really optional. Stephen Toub has a good blog post on the difference between StartNew and Run and why Run is (usually) better for async code.

Update from @usr comment below: LongRunning only applies to the beginning of the async method (up until the first incomplete operation is awaited). So it's almost certainly better all around to use Task.Run in this case.

like image 55
Stephen Cleary Avatar answered Oct 19 '22 18:10

Stephen Cleary