C# Task.Run和Task.Factory.StartNew之间的异常处理不同

C# Task.Run和Task.Factory.StartNew之间的异常处理不同,c#,exception,task-parallel-library,taskfactory,C#,Exception,Task Parallel Library,Taskfactory,我在使用Task.Factory.StartNew时遇到一个问题,并试图捕获抛出的异常。在我的应用程序中,我有一个长时间运行的任务,我想将其封装在task.Factory.StartNew(..,TaskCreationOptions.longlunning)中 但是,当我使用Task.Factory.StartNew时,不会捕获异常。然而,当我使用Task.Run时,它就像我期望的那样工作,我认为它只是Task.Factory.StartNew上的一个包装器(例如) 这里提供了一个工作示例,不

我在使用
Task.Factory.StartNew
时遇到一个问题,并试图捕获抛出的
异常。在我的应用程序中,我有一个长时间运行的任务,我想将其封装在
task.Factory.StartNew(..,TaskCreationOptions.longlunning)中

但是,当我使用
Task.Factory.StartNew
时,不会捕获异常。然而,当我使用
Task.Run
时,它就像我期望的那样工作,我认为它只是
Task.Factory.StartNew
上的一个包装器(例如)

这里提供了一个工作示例,不同之处在于在使用
Task.Run
时将异常写入控制台,但在使用
Factory.StartNew
时不会写入控制台

我的问题是:
如果我有一个长时间运行的任务有可能抛出异常,我应该如何在调用代码中处理它们

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

}
private static void Main(字符串[]args)
{
任务t=runlongstask();
t、 等待();
控制台写入线(t.Result);
Console.ReadKey();
}
专用异步静态任务RunLongTask()
{
尝试
{
等待RunTaskAsync();
}
捕获(例外e)
{
控制台写入线(e);
返回false;
}
Console.WriteLine(“成功”);
返回true;
}
专用静态任务RunTaskAsync()
{
//返回任务。运行(异步()=>
//    {
//抛出新异常(“我的异常”);
//    });
return Task.Factory.StartNew(
异步()=>
{
抛出新异常(“我的异常”);
});
}

您的问题是
StartNew
任务不一样。请使用
async
委托运行
StartNew
的返回类型为
Task
(可转换为
Task
)。“外部”
任务
表示方法的开始,“内部”
任务
表示方法的完成(包括任何异常)

要进入内部
任务
,可以使用
展开
。或者您可以只使用
任务。运行
而不是
StartNew
来执行
async
代码<代码>长时间运行
只是一个优化提示,实际上是可选的


从下面的@usr comment更新:
LongRunning
仅适用于
async
方法的开头(直到第一个不完整的操作
wait
ed)。因此,几乎可以肯定的是,在所有方面都使用
任务会更好。在这种情况下,运行

当您第一次执行任务时,应该可以:

await RunTaskAsync().Unwrap();
或者:

await await RunTaskAsync();

我将把我的一些评论归纳成一个答案,因为它们被证明是有帮助的:

longlunning
与在实践中强制创建新线程相同。您的异步方法可能很长一段时间不在该线程上(它在第一个等待点被取消)。在这种情况下,你不想长跑

异步方法运行多长时间无关紧要。线程在第一次等待(对未完成的任务进行操作)时被销毁

编译器能否以任何方式使用此提示?编译器通常无法以任何主要方式分析代码。此外,编译器对TPL一无所知。第三方物流是一个图书馆。这个库总是会启动一个新线程。指定
LongRunning
iff您的任务几乎总是会在几秒钟内消耗100%的CPU,或者很可能会阻塞几秒钟


我猜你不想在这里运行
长时间运行
,因为如果你在阻塞,为什么首先要使用异步?async是指不阻塞而是脱离线程。

如果执行Task.Factory.StartNew(someAction,CancellationToken.None,TaskCreationOptions.DenyChildataTach,TaskScheduler.Default),会发生什么情况?@MatthewWatson是的,不幸的是相同的结果,请参见此处:(结尾处的一条评论提出了类似的问题)@马修沃森我看不出有什么评论。。尼克的代码似乎只处理了
wait Task.Run(()=>…
wait Task.Run(异步)之间的差异=>..
嗯,是的,我假设异步的东西与它有关。也许不是!在我的工作中,我们被鼓励使用这些优化提示。如果我不将其转换为
异步无效
而使用
工厂的返回值,会更好吗。StartNew
(这可能吗)?为了减少混淆,我建议将其作为一种单独的方法。也请阅读Stephen Toub的博文;如果您将较旧的
StartNew
与较新的
async
代码一起使用,您可能还想调用
Unwrap
。我的回答不正确;这不是lambda转换导致的问题。这是
任务的包装ode>。我已将我的答案更新为…嗯…对。:)长时间运行等同于在实践中强制创建新线程。并且您的异步方法可能很长时间不在该线程上(它在第一个等待点被取消)。在这种情况下,您不希望长时间运行。@默认情况下,编译器通常无法以任何主要方式分析您的代码。此外,编译器对TPL一无所知。TPL是一个库。此库将始终启动一个新线程。如果您的任务几乎总是消耗100%的CPU数秒或wi,请指定长时间运行我很可能会阻塞几秒钟。你有没有关于在第一个等待点被截获的
长时间运行
的参考资料?我想了解更多it@Default等待将在操作完成时执行的回调排队。完成后,它总是从函数返回。TPL看到返回d结束任务(和线程)(记住,这里有两个任务-参见Stephen