CallContext.LogicalGetData得到恢复,即使在没有不同步。为什么? [英] CallContext.LogicalGetData gets restored even where there is no asynchrony. Why?

查看:950
本文介绍了CallContext.LogicalGetData得到恢复,即使在没有不同步。为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到 CallContext.LogicalSetData / LogicalGetData 不工作,我希望他们做的方式。内部的设置的值异步方法被恢复的即使没有不同步或任何形式的线程切换,任何。

I noticed that CallContext.LogicalSetData/LogicalGetData don't work the way I expected them to do. A value set inside an async method gets restored even when there is no asynchrony or any kind of thread switching, whatsoever.

下面是一个简单的例子:

Here is a simple example:

using System;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication
{
    class Program
    {
        static async Task<int> TestAsync()
        {
            CallContext.LogicalSetData("valueX", "dataX");
            // commented out on purpose
            // await Task.FromResult(0); 
            Console.WriteLine(CallContext.LogicalGetData("valueX"));
            return 42;
        }

        static void Main(string[] args)
        {
            using(ExecutionContext.SuppressFlow())
            {
                CallContext.LogicalSetData("valueX", "dataXX");
                Console.WriteLine(CallContext.LogicalGetData("valueX"));
                Console.WriteLine(TestAsync().Result);
                Console.WriteLine(CallContext.LogicalGetData("valueX"));
            }
        }
    }
}

它产生这样的输出:

It produces this output:


dataXX
dataX
42
dataXX

如果我让 TestAsync 非异步,它按预期工作:

If I make TestAsync non-async, it works as expected:

static Task<int> TestAsync()
{
    CallContext.LogicalSetData("valueX", "dataX");
    Console.WriteLine(CallContext.LogicalGetData("valueX"));
    return Task.FromResult(42);
}

输出:


dataXX
dataX
42
dataX

我能够理解这种行为,如果我有在 TestAsync 一些真正的不同步,但这不是这里的情况。我甚至用 ExecutionContext.Sup pressFlow ,但是这并不能改变什么。

I would understand this behavior if I had some real asynchrony inside TestAsync, but that's not the case here. I even use ExecutionContext.SuppressFlow, but that doesn't change anything.

可能有人请解释为什么是这样工作的?

Could someone please explain why it works this way?

推荐答案

在这种情况下,正如预期的那样对于不同的人不同。 :)

"As expected" in this case is different for different people. :)

在原来的异步CTP(没有修改任何框架code),有一个异步本地之类的背景下,在所有的不支持。 MS修改 LocalCallContext 在.NET 4.5中添加这种支持。旧的行为(具有共享逻辑上下文)是<一个href="https://social.msdn.microsoft.com/Forums/en-US/ea21ca57-5340-439c-8ee9-f0185b5787a1/callcontext-what-are-the-recommendations-for-using-this-going-forwards?forum=async"相对=nofollow>特别是异步并发(即 Task.WhenAll )。

In the original Async CTP (which did not modify any framework code), there was no support for an "async-local" kind of context at all. MS modified the LocalCallContext in .NET 4.5 to add this support. The old behavior (with a shared logical context) is especially problematic when working with asynchronous concurrency (i.e., Task.WhenAll).

我解释href="http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html" rel="nofollow"> <$ C $高级技工 LocalCallContext 异步 的方法在我的博客。关键就在这里:

I explain the high-level mechanics of LocalCallContext within async methods on my blog. The key is here:

当一个异步方法开始,它会通知其逻辑调用上下文激活副本上写的行为。

When an async method starts, it notifies its logical call context to activate copy-on-write behavior.

有一个特殊的副本上写标志在逻辑调用上下文多数民众赞成翻转每当异步方法开始执行的。这是由异步状态机(特别是,在当前的实现, AsyncMethodBuilderCore.Start 调用<$ C $完成C> ExecutionContext.EstablishCopyOnWriteScope )。而标志是一种简化 - 有没有实际的布尔成员或任何东西;它只是修改的方式,未来将写入(浅)复制的逻辑调用上下文状态( ExecutionContextBelongsToCurrentScope 和朋友)。

There's a special copy-on-write flag in the logical call context that's flipped on whenever an async method starts executing. This is done by the async state machine (specifically, in the current implementation, AsyncMethodBuilderCore.Start invokes ExecutionContext.EstablishCopyOnWriteScope). And "flag" is a simplification - there's no actual boolean member or anything; it just modifies the state (ExecutionContextBelongsToCurrentScope and friends) in a way that any future writes will (shallow) copy the logical call context.

这是相同的状态机的方法(启动)将调用 ExecutionContextSwitcher.Undo 只要它是与同步的一部分进行的异步方法。这就是恢复以前的逻辑背景。

That same state machine method (Start) will call ExecutionContextSwitcher.Undo whenever it is done with the synchronous part of the async method. This is what is restoring the former logical context.

这篇关于CallContext.LogicalGetData得到恢复,即使在没有不同步。为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆