是否有可能知道AsyncLocal何时被最终失效?



请考虑我在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的执行范围结束,使环境值无效。 我想做的是知道何时发生这种情况,并有一个事件和/或某种触发器在发生时通知我。

在上面的三个测试中,ExpectedExpectedAsync打印出"Invalidated!"消息一次,这是我的方案的预期(所需)行为。

但是,UnexpectedAsync打印此消息两次。 对于我的方案来说,这是一个问题,因为失效应该只发生一次,并且只有在创建AsyncLocal的上下文的执行完成执行时。

据我了解,UnexpectedAsync的任务是将控制权交给异步基础架构(第一次失效),然后将控制权恢复回原始上下文(UnexpectedAsync),然后又完成(第二次失效)。

我在这里要实现的是确保AsyncLocal在上述所有演示场景中最终失效一次。 也就是说,我想确定AsyncLocal的执行上下文何时完成并且不再有效。 这可能吗?

您正在经历的是记录在案的行为。

只要有上下文切换,就会调用通知方法。Task.Yield会导致上下文切换。然后,Yield 完成,并且有一个上下文切换回来以检查可等待(已完成或出错)的状态,然后运行异步工作的线程完成。

在您的澄清中,您使用了术语"已完成事件":最好将其称为"上下文切换事件"。这会给你一个更好的心智模型。

回答您的问题:一旦任务完成或出现故障,上下文将失效。等待任务会告诉你这一点,或者你可以检查任务的 IsDone 或 IsFaulted 属性。

最新更新