如果 ConfigurAwait 设置为 False,任务不会进入故障状态

Task doesn't Go to Faulted State If ConfigurAwait set to False

这就是我要实现的目标。我启动了一项任务,但没有对其执行 wait/result。为确保启动的任务进入故障状态(例如抛出异常),我通过在 Continuation 中调用 Environment FailFast 来使进程崩溃。

我面临的问题是,如果我 运行 下面的代码,在 ContinueWith 内部,任务状态(抛出异常)显示为 "RanToCompletion"。我预计它会是故障状态。

    private Task KickOfTaskWorkAsync()
    {
        var createdTask = Task.Run(() => this.RunTestTaskAsync(CancellationToken.None).ConfigureAwait(false), CancellationToken.None);

        createdTask.ContinueWith(
            task => Console.WriteLine("Task State In Continue with => {0}", task.Status));

        return createdTask;
    }

    private async Task RunTestTaskAsync(CancellationToken cancellationToken)
    {
        throw new Exception("CrashingRoutine: Crashing by Design");
    }

这真的是 st运行ge :( 如果我删除 Task.Run 函数调用中的 'ConfigureAwait(false)',任务确实会进入 Continue with 中的 Faulted 状态。真的很茫然解释发生了什么,希望得到社区的帮助。

[更新]: 我的同事指出了一个明显的错误。我在 Test.Run 中调用 RunTestAsync 时正在使用 ConfigureAwait,即使我不等待它。在这种情况下,ConfigureAwait 不会 return 任务到 Task.Run。如果我不调用 ConfigureAwait,任务会得到 returned 并且事情会按预期工作。

您的错误是更广泛错误类别的一个具体示例:您没有观察到您真正关心的Task

在您的代码示例中,RunTestTaskAsync() return 是一个 Task 对象。它同步完成(因为没有 await),因此 Task 对象 returns 在方法 returns 时由于异常已经出错。然后,您的代码会在这个错误的 Task 对象上调用 ConfigureAwait()

但是所有这些都发生在 另一个 Task 中,即您调用 Task.Run() 时开始的那个。这个 Task 没有做任何事情来观察异常,所以它正常完成。

您在删除 ConfigureAwait() 调用时观察到异常的原因与调用本身无关。如果您离开呼叫并改为传递 true,您仍然无法观察到异常。删除调用时可以观察到异常的原因是,在没有调用 ConfigureAwait() 的情况下,lambda 表达式的 return 值为 Task,并且调用 a different overload of Task.Run().

这个重载与其他重载有点不同。来自文档:

Queues the specified work to run on the thread pool and returns a proxy for the task returned by function.

也就是说,虽然它仍然启动一个新的 Task,但它 returns 代表的 Task 对象不是 Task,而是 return 由您的 lambda 表达式编辑。该代理采用与它包装的 Task 相同的状态,因此您看到它处于 Faulted 状态。

根据您发布的代码,我认为您一开始就不应该调用 Task.Run()。以下方法同样有效,没有代理的开销和复杂性:

static void Main(string[] args)
{
    Task createdTask = RunTestTaskAsync();

    createdTask.ConfigureAwait(false);

    createdTask.ContinueWith(
        task => Console.WriteLine("Task State In Continue with => {0}", task.Status)).Wait();
}

private static async Task RunTestTaskAsync()
{
    throw new Exception("CrashingRoutine: Crashing by Design");
}

(我删除了 CancellationToken 值,因为它们与您的问题完全无关,在这里完全是多余的。)