gpt4 book ai didi

c# - ThreadContextChanged 上的 AsyncLocal 值更新为 null

转载 作者:可可西里 更新时间:2023-11-01 08:13:10 27 4
gpt4 key购买 nike

我正在尝试了解 AsyncLocal 在 .Net 4.6 中的工作方式。我正在将一些数据放入 AsyncLocal...但是当 ThreadContext 更改时它被设置为 null。我使用 AsyncLocal 的全部原因是在等待异步操作时尝试跨线程保留/缓存此值。知道为什么会在上下文更改时专门调用它并将其设置为 null 吗?关于 AsyncLocal 的文档非常稀少……也许我完全弄错了。

public class RequestContextProvider : IRequestContextProvider
{
private static readonly AsyncLocal<IRequestContext> _requestContext = new AsyncLocal<IRequestContext>(ValueChangedHandler);

private static void ValueChangedHandler(AsyncLocalValueChangedArgs<IRequestContext> asyncLocalValueChangedArgs)
{
**//This is just here to observe changes...when I await a call that
//causes control to pass to a different thread..this is called
//with a current value of null.**
var previousValue = asyncLocalValueChangedArgs.PreviousValue;
var currentValue = asyncLocalValueChangedArgs.CurrentValue;
var contextChanged = asyncLocalValueChangedArgs.ThreadContextChanged;
}

public void SetContext(IRequestContext requestContext)
{
_requestContext.Value = requestContext;
}

public IRequestContext GetContext()
{
return _requestContext.Value;
}

}

这是调用方式的示例。这是一个使用 EventStore 连接 (GetEventStore.com) 调用的异步事件订阅者。如果这里的两个等待任务什么都不做(如果没有要查找的 ID)我没有问题,因为任务可能是同步运行的。但如果我确实有工作要做这些任务,我就会失去我的背景。

 private async Task PublishProduct(Guid productId, Guid productReferenceId, IEnumerable<Guid> disclosureIds,
IEnumerable<Guid> addOnIds)
{
var disclosureReferenceIdsTask = _disclosureReferenceIdService.GetReferenceIdsAsync(disclosureIds);
var addOnReferenceIdsTask = _addOnReferenceIdService.GetReferenceIdsAsync(addOnIds);
await Task.WhenAll(disclosureReferenceIdsTask, addOnReferenceIdsTask);

IEnumerable<Guid> disclosuresResult = await disclosureReferenceIdsTask;
IEnumerable<Guid> addOnsResult = await addOnReferenceIdsTask;

await _eventPublisher.PublishAsync(new ProductPublished(productId, productReferenceId,
disclosuresResult.ToList(), addOnsResult.ToList()));
}

这是我看似可行的 hacky 解决方案:

    private static void ValueChangedHandler(AsyncLocalValueChangedArgs<IRequestContext> asyncLocalValueChangedArgs)
{
var previousValue = asyncLocalValueChangedArgs.PreviousValue;
var currentValue = asyncLocalValueChangedArgs.CurrentValue;
var contextChanged = asyncLocalValueChangedArgs.ThreadContextChanged;
if (contextChanged && currentValue == null && previousValue != null)
{
_requestContext.Value = previousValue;
}
}

仅供引用,这是一个在 DNX RC1 下作为控制台应用程序运行的 4.6 运行时项目。

最佳答案

你需要做的是:ExecutionContext.SuppressFlow();
当你的线程上下文丢失时,这将停止引发事件 valueChangedHandler ,结果你将不会得到 NULL 值,它也会在创建新的 ThreadContext 和数据时停止引发事件复制到这里。

private static void ValueChanged(AsyncLocalValueChangedArgs<string> obj)
{
Console.WriteLine(obj.CurrentValue);
}

public static void Main(string[] args)
{
ExecutionContext.SuppressFlow();
AsyncLocalContext.Value = "Main";
Task.Run(() =>
{
AsyncLocalContext.Value = "Test1";
}).Wait();

Console.WriteLine("Main: " + AsyncLocalContext.Value);
}

输出是:

Main
Test1
Main: Main

如果我们评论 ExecutionContext.SuppressFlow(); 那么会得到这个:

Main
Main -- copied data to Task
Test1
-- here is NULL when context has lost
Main: Main

关于c# - ThreadContextChanged 上的 AsyncLocal 值更新为 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35802014/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com