How to explain await/async Synchronization Context switching behavior

后端 未结 1 1415
小蘑菇
小蘑菇 2021-01-18 23:34

There are a couple of things (but 1 main thing) that I don\'t understand about the behavior of the following code.

Can someone help explain this?

It\'s actu

1条回答
  •  迷失自我
    2021-01-19 00:33

    2.2 Is quite simple to explain, 1.2 not as easy.

    The reason 2.2 prints null is due to when you await using the default (new SynchronizationContext) or null SynchronizationContext, the Post method will get called passing in the continuation delegate, this is scheduled on the ThreadPool. It makes no effort to restore the current instance, it relies on the current SynchronizationContext being null for these continuations when they run on the ThreadPool (which it is). To be clear, because you are not using .ConfigureAwait(false) your continuation will get posted to the captured context as you are expecting, but the Post method in this implementation doesn't preserve/flow the same instance.

    To fix this (i.e. make your context "sticky"), you could inherit from SynchronizationContext, and overload the Post method to call SynchronizationContext.SetSynchronizationContext(this) with the posted delegate (using Delegate.Combine(...)). Also, the internals treat SynchronizationContext instances the same as null in most places, so if you want to play with this stuff, always create an inheriting implementation.

    For 1.2, this actually surprised me also, as my understanding was that this would call the underlying state machine (along with all the internals from AsyncMethodBuilder), but it would be called synchronously while maintaining its SynchronizationContext.

    I think what we are seeing here is explained in this post, and it's to do with ExecutionContext being captured and restored inside of the AsyncMethodBuilder / async state machine, this is protecting and preserving the calling ExecutionContext and hence SynchronizationContext. Code for this can been seen here (thanks @VMAtm).

    0 讨论(0)
提交回复
热议问题