Different exception handling between Task.Run and

2019-08-16 19:19发布

我遇到一个问题,当我使用Task.Factory.StartNew ,并试图捕捉到一个exception时引发。 在我的应用我有,我想在一个封装一个长期运行的任务Task.Factory.StartNew(.., TaskCreationOptions.LongRunning);

然而,当我使用的异常没有被捕获Task.Factory.StartNew 。 然而工作,我希望当我使用Task.Run ,我认为是只是一个包装Task.Factory.StartNew (按照例如这个MSDN文章 )。

工作示例这里提供,不同之处在于例外写入使用时安慰Task.Run ,但使用时不Factory.StartNew

我的问题是:
如果我有一个LongRunning有抛出异常的可能性,我该如何处理这些调用代码的任务?

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");
    });

}

Answer 1:

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.



Answer 2:

我拉我的一些评论到答案,因为他们原来是有帮助的:

LongRunning等同于强制在实践中创造了一个新的线程。 而你的异步方法可能不是上线很长时间(它是采取关闭在第一的await点)。 你不想LongRunning在这种情况下。

不要紧多久异步方法运行。 线程是在第一个的await破坏(即在未完成任务的工作)。

编译器可以使用此提示以任何方式? 编译器一般不能分析任何主要方式你的代码。 另外,编译器不知道的东西TPL。 第三方物流是一个图书馆。 而这个图书馆将永远只是推出一个新的线程。 指定LongRunning当且仅当你的任务几乎总是燃烧100%的CPU多秒,或将多个秒封锁概率非常高。

我的猜测是你不想LongRunning因为如果你封锁,你为什么要摆在首位使用异步这里? 异步大约是不会阻止,但下车的线程。



Answer 3:

它应该是可能的,当你第一次解开任务:

await RunTaskAsync().Unwrap();

或者:

await await RunTaskAsync();


文章来源: Different exception handling between Task.Run and Task.Factory.StartNew