Task.Continue与前一个任务的相同上下文

时间:2018-03-05 14:25:56

标签: c# async-await task

我有以下示例

    [TestMethod]
    public void AsyncLocalFlowsInContinuation()
    {
        AsyncLocal<int> local = new AsyncLocal<int>();

        var task1 = Task.Run(() =>
        {
            local.Value = 1;
        });

        local.Value.Should().Be(0);                       

        var t1c = task1.ContinueWith((r) =>
        {
            local.Value.Should().Be(1); //THROW: it is 0 instead
        });

        local.Value.Should().Be(0);

        t1c.Wait();
    }

这不应该开箱即用吗?在我的理解中,AsyncLocal应该像每个任务的静态但特定的一样(例如,适用于在“task1”中创建的子任务),但它在连续任务“t1c”中似乎没有相同的值。我应该指定一些东西来允许ExecutionContext在延续任务中正确地流动吗?或者我错过了一些obvuois?

我正在瞄准.Net Standard 2.0,这里不一定要使用AsyncLocal,如果它是错误的类型,只要测试的语义保持不变,我就会乐意使用另一个。< / p>

2 个答案:

答案 0 :(得分:0)

晚了3年,但是无论如何...之所以发生,是因为Task延续不是它们继续执行的Task的嵌套任务。它们在前一个任务的调用者的上下文中执行。也就是说,例如,如果您的单元测试是异步测试,则延续将是测试方法本身的嵌套Task,并且可以访问它的异步本地状态(如果有)。

这不会改变延续是否返回Task

但是,重要的是,如果延续确实返回了Task,例如它使用了Task.Run并返回了其Task结果,那么就存在一个“技巧”表现正确:

它必须是异步lambda,并在其内部等待任务,或使用Unwrap()

请参见https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/chaining-tasks-by-using-continuation-tasks#continuations-that-return-task-types

答案 1 :(得分:-1)

任务正常运行并且根据预期的执行流程。但是,问题出在AsyncLocal<T>类,用于

  

表示给定异步控件的本地环境数据   流,例如异步方法。

换句话说,分配给local变量的数据对于它所使用的线程上下文是本地的。因此,变量有三个不同的“版本”:一个用于主线程,另一个用于主线程对于第一个任务的上下文,以及最后一个继续任务。每个都有不同的价值。

如果您使用普通的整数数据类型(int),您将获得预期的值。

请参阅以下链接以获取更多信息:

https://msdn.microsoft.com/en-us/library/dn906268(v=vs.110).aspx

Safety of AsyncLocal in ASP.NET Core