如何解释等待/异步同步上下文切换行为 - c#

我对以下代码的行为有几件事情(但有一件主要事情)不了解。

有人可以帮忙解释一下吗?

它实际上是非常简单的代码-只是一个常规方法调用异步方法。在异步方法中,我使用using块尝试临时更改SynchronizationContext。

在代码的不同点,我探查了当前的SynchronizationContext。

这是我的问题:

当执行到达位置“ 2.1”时,上下文已更改为
上下文2。好的。然后,因为我们点击了“ await”,所以任务是
返回并执行跳回到位置“ 1.2”。为什么然后
位置1.2,上下文是否不“粘在”上下文2?
也许using语句和异步方法正在发生一些魔术?

在位置2.2,为什么上下文不是上下文#2?上下文是否不应该延续到“继续”(“ await”之后的语句)中?

码:

    public class Test
    {
        public void StartHere()
        {
            SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());

            this.logCurrentSyncContext("1.1"); // Context #1
            Task t = f();
            this.logCurrentSyncContext("1.2"); // Context #1, why not Context #2?
            t.Wait();
            this.logCurrentSyncContext("1.3"); // Context #1
        }


        private async Task f()
        {
            using (new ThreadPoolSynchronizationContextBlock())
            {
                this.logCurrentSyncContext("2.1");  // Context #2
                await Task.Delay(7000);
                this.logCurrentSyncContext("2.2");  // Context is NULL, why not Context #2?
            }

            this.logCurrentSyncContext("2.3");  // Context #1
        }


        // Just show the current Sync Context. Pass in some kind of marker so we know where, in the code, the logging is happening

        private void logCurrentSyncContext(object marker)
        {
            var sc = System.Threading.SynchronizationContext.Current;
            System.Diagnostics.Debug.WriteLine(marker + " Thread: " + Thread.CurrentThread.ManagedThreadId + " SyncContext: " + (sc == null? "null" : sc.GetHashCode().ToString()));
        }

        public class ThreadPoolSynchronizationContextBlock : IDisposable
        {
            private static readonly SynchronizationContext threadpoolSC = new SynchronizationContext();

            private readonly SynchronizationContext original;

            public ThreadPoolSynchronizationContextBlock()
            {
                this.original = SynchronizationContext.Current;
                SynchronizationContext.SetSynchronizationContext(threadpoolSC);
            }

            public void Dispose()
            {
                SynchronizationContext.SetSynchronizationContext(this.original);
            }
        }
    }

结果:

1.1 Thread: 9 SyncContext: 37121646 // I call this "Context #1"
2.1 Thread: 9 SyncContext: 2637164 // I call this "Context #2"
1.2 Thread: 9 SyncContext: 37121646
2.2 Thread: 11 SyncContext: null
2.3 Thread: 11 SyncContext: 37121646
1.3 Thread: 9 SyncContext: 37121646

参考方案

2.2解释很简单,1.2不那么容易。

2.2打印null的原因是由于当您使用默认(await)或new SynchronizationContext SynchronizationContext null时,将调用Post方法传入延续委托,即is scheduled on the ThreadPool。当它们在ThreadPool(实际上是)上运行时,它们不依赖于当前SynchronizationContext作为null的这些继续,因此无需进行任何操作来还原当前实例。需要明确的是,由于您没有使用.ConfigureAwait(false),您的延续将被发布到捕获的上下文中,正如您所期望的那样,但是此实现中的Post方法不会保留/流动相同的实例。

要解决此问题(即,使上下文变为“粘性”),您可以继承SynchronizationContext,并重载Post方法以使用已发布的委托调用SynchronizationContext.SetSynchronizationContext(this)(使用Delegate.Combine(...))。此外,内部对象在大多数地方将SynchronizationContext实例与null相同,因此,如果您想玩这些东西,请务必创建一个继承实现。

对于1.2,这实际上也让我感到惊讶,因为我的理解是这将调用底层状态机(以及AsyncMethodBuilder中的所有内部信息),但是在保持其SynchronizationContext的同时会被同步调用。

我认为我们在这里看到的内容已在in this post中进行了解释,这与在AsyncMethodBuilder /异步状态机内部捕获并恢复ExecutionContext有关,这是在保护和保留调用ExecutionContext并因此保留SynchronizationContext。此can been seen here的代码(感谢@VMAtm)。

当回复有时是一个对象有时是一个数组时,如何在使用改造时解析JSON回复? - java

我正在使用Retrofit来获取JSON答复。这是我实施的一部分-@GET("/api/report/list") Observable<Bills> listBill(@Query("employee_id") String employeeID); 而条例草案类是-public static class…

改造正在返回一个空的响应主体 - java

我正在尝试使用Retrofit和Gson解析一些JSON。但是,我得到的响应机构是空的。当我尝试从对象中打印信息时,出现NullPointerException。我确保URL正确,并且我也确保POJO也正确。我正在使用jsonschema2pojo来帮助创建POJO类。这是我要解析的JSON{ "?xml": { "@versi…

jQuery删除和$(this) - php

我在remove()方法上遇到问题。我无法删除$(this)对象。我的代码是:$(".submit_add_type").live("click", function() { var parent = $(this).parent(); var type_value = parent.children('.t…

如何正确增加喜欢和不喜欢的人 - javascript

我在每个帖子上都有一个按钮1)点赞按钮如果用户已经喜欢了该帖子,则显示“与众不同”按钮如果用户不喜欢该帖子,则为HTML部分<a href="javascript:void(0);" id="liker" data-count="0" data-fpc="481" data…

每个文件合并后添加换行 - python

我有很多类似以下内容的JSON文件:例如。1.json{"name": "one", "description": "testDescription...", "comment": ""} test.json{"name"…