为什么AsyncLocal <t>在稍微重构代码时会返回不同的结果?

时间:2018-03-12 10:04:12

标签: c# .net async-await

当我呼叫WrapperAsync AsyncLocalContext.Value时,返回null。当我在方法之外运行相同的代码块时,在Main方法中,AsyncLocalContext.Value不为空(这是我所期望的)。

功能完全相同但结果不同。这是Asynclocal类的错误还是有其他解释?

internal class Program
{
    private static readonly AsyncLocal<string> AsyncLocalContext = new AsyncLocal<string>();

    private static void Main()
    {
        const string text = "surprise!";

        WrapperAsync(text).Wait();
        Console.WriteLine("Get is null: " + (AsyncLocalContext.Value == null));
        // AsyncLocalContext.Value is null

        var value = GetValueAsync(text).Result;
        AsyncLocalContext.Value = value;
        Console.WriteLine("Get is null: " + (AsyncLocalContext.Value == null));
        // AsyncLocalContext.Value is not null
        Console.Read();
    }

    private static async Task WrapperAsync(string text)
    {
        var value = await GetValueAsync(text);
        AsyncLocalContext.Value = value;
    }

    private static async Task<string> GetValueAsync(string text)
    {
        await Task.Delay(0);
        return text;
    }
}

2 个答案:

答案 0 :(得分:1)

请点击此链接AsyncLocal Class on MSDN

  

AsyncLocal<T>表示给定异步控制流本地的环境数据,例如异步方法

这意味着当您的代码从另一个async方法访问时使用不同的值,例如WrapperAsync,并且您的主线程包含其他值

[更新]
不明白的事情要理解,但这里是解释。 Control Flow in Async Programs。这就是你不希望这样做时你的线程被改变的方式。

这就是控制流如何使用async

public class Program
{
    private static readonly AsyncLocal<string> AsyncLocalContext = new AsyncLocal<string>();

    public static void Main(string[] args)
    {
        AsyncLocalContext.Value = "No surprise";
        WrapperAsync("surprise!");
        Console.WriteLine("Main: " + AsyncLocalContext.Value);
    }

    private static async void WrapperAsync(string text)
    {
        Console.WriteLine("WrapperAsync before: " + AsyncLocalContext.Value);
        AsyncLocalContext.Value = text;
        Console.WriteLine("WrapperAsync after: " + AsyncLocalContext.Value);
    }
}

输出是:

WrapperAsync before: No surprise
WrapperAsync after: surprise!
Main: No surprise

[/更新]

答案 1 :(得分:0)

AsyncLocal<T>是存储在当前线程的ExecutionContext中的环境数据。 ExecutionContext在异步/等待调用链中自动跨线程流动(有关详细信息,请参见Stephen Toub的blog)。应用启动时,将使用默认的ExecutionContext,但是一旦通过AsyncLocal<T>.Value存储了数据,就会为当前的异步调用链创建一个新的ExecutionContext(请参见here)并将环境数据添加到其中。此新上下文将传播到下游调用。

Stephen Cleary讨论了此行为here(向下滚动到AsyncLocal部分)并指出:

  

[AsyncLocal]为上下文信息提供了一种“向下”传递的方式   异步调用。请注意,该值不会“向上”流动。

这就是为什么调用链上的AsyncLocal<T>更新没有反映在上游方法中的原因。