C# 任务不存在';如果ConfigurAwait设置为False,则不会进入故障状态
这就是我想要实现的目标。我启动了一项任务,但不等待它的结果。为了确保如果启动的任务进入故障状态(例如,抛出异常),我在Continuation中调用Environment FailFast使进程崩溃 我所面临的问题是,如果我在ContinueWith中运行下面的代码,任务的状态(引发异常)将显示为“RanToCompletion”。我以为这是一个错误的状态C# 任务不存在';如果ConfigurAwait设置为False,则不会进入故障状态,c#,asynchronous,parallel-processing,task,configureawait,C#,Asynchronous,Parallel Processing,Task,Configureawait,这就是我想要实现的目标。我启动了一项任务,但不等待它的结果。为了确保如果启动的任务进入故障状态(例如,抛出异常),我在Continuation中调用Environment FailFast使进程崩溃 我所面临的问题是,如果我在ContinueWith中运行下面的代码,任务的状态(引发异常)将显示为“RanToCompletion”。我以为这是一个错误的状态 private Task KickOfTaskWorkAsync() { var createdTask =
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)',任务在Continue with中确实会进入错误状态。我真的无法解释发生了什么,希望社区能提供一些帮助
[更新]:我的同事指出了一个明显的错误。我在测试中调用RunTestAsync时正在使用ConfigureAwait。即使我不等待它,也要运行。在这种情况下,ConfigureAwait不会将任务返回到Task.Run。如果我不调用ConfigureAwait,则会返回一个任务并按预期工作。您的错误就是一个特定的b类错误示例roader错误类别:你没有观察到你真正关心的
任务
在您的代码示例中,RunTestTaskAsync()
返回一个Task
对象。它同步完成(因为没有await
),因此当方法返回时,由于异常,它返回的Task
对象已经出现故障。然后,您的代码调用ConfigureAwait()
在此故障的任务
对象上
但所有这些都发生在另一个任务中,即在调用Task.Run()
时启动的任务。此任务
不会观察异常,因此它正常完成
删除ConfigureAwait()时观察异常的原因
调用与调用本身无关。如果您离开调用并传递了true
,您仍然无法观察到异常。删除调用时可以观察到异常的原因是,没有调用configurewait()
,lambda表达式的返回值是一个任务
,此函数调用
此重载与其他重载略有不同。从文档中可以看出:
对要在线程池上运行的指定工作进行排队,并为函数返回的任务返回代理
也就是说,虽然它仍然启动一个新的任务
,但它返回的任务
对象并不代表该任务
,而是由lambda表达式返回的对象。该代理与它包装的任务
具有相同的状态,因此您可以在故障
状态中看到它
根据您发布的代码,我认为您首先不应该调用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
值,因为它们与您的问题毫无关系,在这里是完全多余的。)您使用ContinueWith
有什么原因吗?ContinueWith
是针对异步等待前的时代;现在您可以使用await RunTestTaskAsync()
后接Console.WriteLine()
并以更标准的方式捕获您想要的任何异常;即尝试。catch
@sellotape:现在wait
是一种更惯用的处理连续性的方法,这是正确的。但是,OP即使使用wait
,也会有同样的问题。他们将等待错误的任务ect并仍会看到任务处于非故障状态。@PeterDuniho-如果他要等待createdTask
,那么是的,但如果他只是等待RunTestTaskAsync()
(这似乎没有什么理由不这样做,但我想没有足够的上下文来确定),catch
将捕获他抛出的异常。@sellotape:“如果他只是等待RunTestTaskAsync()”——但他不是。他不是。这是他问题的全部症结所在。我的观点是,仅仅告诉他使用await
根本不能解决他的问题。如果ContinueWith()
被替换为wait
在这里,同样的问题仍然会发生。问题只是稍微改写了代码。@PeterDuniho-我不是说这是一个答案;而只是OP可能会发现有用的相关信息,这就是为什么我发表了评论,而不是答案(你的答案涵盖了问题)。我在第一条评论中也特别提到了await runtesttaskaync()
。在没有相应的await
的情况下配置await
(即createdTask.ConfigureAwait(false)
)有什么意义?更仔细地看,代码似乎从未运行过(在此之前会引发异常).@ta.speot.is:对configurewait()
的调用会影响延续,无论是通过ContinueWith()完成的
或wait
语句。对于异常,您也弄错了。线程中没有观察到异常,因为它是由方法返回的任务
封装的。如果您费心运行代码,您会知道的。有趣的是,人们投票时没有真正理解他们在看什么。RE:#1我在下面impressionConfigureAwait
返回一个ConfiguredTaskAwaitable
,这就是保存配置的东西。你是对的re:#2.@ta.speot.is:是的,它是正确的。你必须通过一个调度程序来继续()。等待被丢弃,没有任何效果。不过,问题的关键是答案是正确的,代码的编写只是为了尽可能接近原始问题的代码,同时提供符合OP期望的行为。几乎不值得向下投票,因为原始代码是我