如果 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
值,因为它们与您的问题完全无关,在这里完全是多余的。)
这就是我要实现的目标。我启动了一项任务,但没有对其执行 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
值,因为它们与您的问题完全无关,在这里完全是多余的。)