考虑我在xUnit测试类中使用的以下代码:
public sealed class AsyncLocalTests
{
readonly ITestOutputHelper _output;
public AsyncLocalTests(ITestOutputHelper output) => _output = output;
[Fact]
void Expected()
=> new AsyncLocal<object>(args =>
{
if (args.ThreadContextChanged && args.CurrentValue == null)
{
_output.WriteLine("Invalidated!");
}
}) {Value = new object()};
[Fact]
Task ExpectedAsync() => Task.Run(action: Expected);
[Fact]
Task UnexpectedAsync()
=> Task.Run(async () =>
{
new AsyncLocal<object>(args =>
{
if (args.ThreadContextChanged && args.CurrentValue == null)
{
_output.WriteLine("Invalidated!");
}
}) {Value = new object()};
await Task.Yield();
});
}
我正在尝试使用AsyncLocal
为我正在设计的应用程序存储环境值。在某些时候,创建AsyncLocal
的执行范围结束,使环境值无效。我想做的是知道这种情况何时发生并且有某种事件和/或某种触发器在发生时会通知我。
在上面的三个测试中,Expected
和ExpectedAsync
打印出"Invalidated!"
消息一次,这是我的方案的预期(所需)行为。
但是,UnexpectedAsync
会将此消息打印两次。对于我的场景,这是一个问题,因为失效应该只发生一次,并且只有在创建AsyncLocal
的上下文的执行已经完成执行时才会发生。
据我了解,UnexpectedAsync
中的任务正在控制异步基础架构(第一次失效),然后控制权重新恢复到原始上下文(UnexpectedAsync
),然后依次进入完成(第二次失效)。
我希望在这里实现的目的是确保AsyncLocal
对于上述所有场景都确定无效。也就是说,我想知道AsyncLocal
的执行上下文何时完成且不再有效。这可能吗?
答案 0 :(得分:2)
您遇到的是documented behavior。
只要有上下文切换,就会调用通知方法。 Task.Yield导致上下文切换。然后,Yield完成,并且有一个上下文切换回来检查等待状态(已完成或出现故障),然后运行异步工作的线程完成。
在您的澄清中,您使用术语&#34;已完成的事件&#34;:最好将其称为&#34;上下文切换事件&#34;。这会给你一个更好的心理模型。
回答您的问题:任务完成或出现故障后,上下文无效。等待任务将告诉您,或者您可以检查任务的IsCompleted或IsFaulted属性。