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

标签 c# exception task-parallel-library taskfactory

我在使用 Task.Factory.StartNew 并 try catch 抛出的 exception 时遇到问题。在我的应用程序中,我有一个长时间运行的任务,我想将其封装在 Task.Factory.StartNew(.., TaskCreationOptions.LongRunning);

但是,当我使用 Task.Factory.StartNew 时,异常没有被捕获。然而,当我使用 Task.Run 时,它的工作方式与我预期的一样,我认为它只是 Task.Factory.StartNew 的包装器(根据例如 this MSDN article ) .

此处提供了一个工作示例,不同之处在于使用 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");
    });

}

最佳答案

你的问题是StartNew不像Task.Run那样工作与 async代表们。 StartNew 的返回类型是Task<Task> (可转换为 Task )。 “外”Task表示方法的开始,“内部”Task表示方法的完成(包括任何异常)。

进入内部Task , 你可以使用 Unwrap .或者你可以只使用 Task.Run而不是 StartNew对于 async代码。 LongRunning只是一个优化提示,实际上是可选的。 Stephen Toub has a good blog post on the difference between StartNew and Run and why Run is (usually) better for async code.

来自@usr 评论的更新: LongRunning只适用于async的开头方法(直到第一个不完整的操作被 await 编辑)。所以使用 Task.Run 几乎肯定更好在这种情况下。

关于c# - Task.Run 和 Task.Factory.StartNew 之间不同的异常处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14729736/

相关文章:

java - 了解 E 类抛出的表达式

c# - 从 QueueUserWorkItem 移动到任务

c# - C#中的Process.Start()对非管理员用户不起作用

c# - WPF动画并按顺序更改图像的不透明度

c# - 多线程丛林中的全局异常处理 - 故障安全/重启

java - 反序列化时出现异常

c# - 在任务中捕获异常的最佳方法是什么?

c# - 等待不调用我的方法,它永远不会返回

c# - Entity Framework 迁移不包括 DefaultValue 数据注释 (EF5RC)

c# - 没有 goto 语句的嵌套 for-each 和 if-else 语句