这就是我要实现的目标。我启动了一个任务,不做等待/结果。为了确保如果启动的任务进入错误状态(例如,抛出异常),我通过在继续中调用环境 FailFast 来使进程崩溃。
我面临的问题是,如果我在代码中运行,则任务的状态(引发异常)将显示为"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");
}
这真是奇怪:(如果我删除 Task.Run 函数调用中的"ConfigureAwait(false)",任务确实会进入"继续"中的错误状态。 真的不知所措地解释发生了什么,并希望得到社区的一些帮助。
[更新]:我的同事指出了一个明显的错误。我在 Test.Run 中调用 RunTestAsync 时正在使用 ConfigureAwait,即使我不等待它。在这种情况下,ConfigureAwait 不会将任务返回到 Task.Run。如果我不调用 ConfigureAwait,任务确实会返回,并且事情会按预期工作。
你的错误是一个更广泛错误类别的具体例子:你没有观察到你真正关心Task
。
在代码示例中,RunTestTaskAsync()
返回一个Task
对象。它同步完成(因为没有await
),因此当方法返回时,由于异常,它返回的Task
对象已经出错。然后,您的代码在此出错的Task
对象上调用ConfigureAwait()
。
但所有这些都发生在另一个Task
,即你打电话时开始Task.Run()
。此Task
不会执行任何操作来观察异常,因此它会正常完成。
删除ConfigureAwait()
调用时观察到异常的原因与调用本身无关。如果您离开呼叫并改为传递true
,您仍然无法观察到异常。删除调用时可以观察到异常的原因是,如果没有对ConfigureAwait()
的调用,lambda 表达式的返回值是一个Task
,这会调用不同的Task.Run()
重载。
此重载与其他重载略有不同。从文档中:
将指定的工作排入队列以在线程池上运行,并返回函数返回的任务的代理。
也就是说,当它仍然启动一个新的Task
时,它返回的Task
对象不代表那个Task
,而是你的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
值,因为它们与您的问题完全无关,在这里完全是多余的。