G
The point is that the method is followed Post() In your context, you're delegating the basic method. A http://referencesource.microsoft.com/mscorlib/R/16705ba05372139e.html Makes the delegate work. pool of flows♪ In the case of UI, this is not the case, because, for example, WinForms context is http://referencesource.microsoft.com/System.Windows.Forms/R/de633159d3cb47c3.html methods. Put the context and current flow into your code:class MySynchronizationContext : SynchronizationContext
{
public override void Post(SendOrPostCallback d, object state)
{
Console.WriteLine($"Post, thread id = {Thread.CurrentThread.ManagedThreadId}");
base.Post(d, state);
}
public override void Send(SendOrPostCallback d, object state)
{
Console.WriteLine($"Send, thread id: {Thread.CurrentThread.ManagedThreadId}");
base.Send(d, state);
}
public override string ToString()
{
return "My";
}
}
public class Program
{
public static void Main(string[] args)
{
SynchronizationContext.SetSynchronizationContext(new MySynchronizationContext());
var browsers = GetBrowsers();
Console.WriteLine("start");
Console.WriteLine(browsers.Result);
}
static async Task<string> GetBrowsers()
{
LogCurrentContext("GetBrowsers prologue");
var res = string.Empty;
var bd = await GetFromFS();
LogCurrentContext("GetBrowsers after GetFromFS");
res += bd; // <-тут могла быть операция с UI
var net = await GetFromNet();
LogCurrentContext("GetBrowsers after GetFromNet");
res += " and " + net; // <-тут могла быть операция с UI
var cpu = await Task.Run<string>(() => { Thread.Sleep(200); return "edge"; });
LogCurrentContext("GetBrowsers after Task.Run");
res += " and " + cpu; // <-тут могла быть операция с UI
return res;
}
private static void LogCurrentContext(string message)
{
Console.WriteLine($"{message}: {(SynchronizationContext.Current?.ToString() ?? "default")} context, thread id = {Thread.CurrentThread.ManagedThreadId}");
}
static async Task<string> GetFromFS()
{
LogCurrentContext("GetFromFS prologue");
using (var sr = new StreamReader(@"D:\GetEventsMarkets.sql"))
{
var res = await sr.ReadToEndAsync();
LogCurrentContext("GetFromFS after ReadToEndAsync");
// тут могла быть операция с UI
return res + " and firefox";
}
}
static async Task<string> GetFromNet()
{
LogCurrentContext("GetFromNet prologue");
await Task.Delay(200);
// тут могла быть операция с UI
LogCurrentContext("GetFromNet after Task.Delay");
return "chrome";
}
}
Most of the time I got this kind of result:GetBrowsers prologue: My context, thread id = 1
GetFromFS prologue: My context, thread id = 1
Post, thread id = 1
GetFromFS after ReadToEndAsync: default context, thread id = 3
start
Post, thread id = 3
GetBrowsers after GetFromFS: default context, thread id = 3
GetFromNet prologue: default context, thread id = 3
GetFromNet after Task.Delay: default context, thread id = 4
GetBrowsers after GetFromNet: default context, thread id = 4
GetBrowsers after Task.Run: default context, thread id = 4
We're interested in two things here.In the caste-based context, there are only gaps in methods GetBrowsers() and GetFromFS()♪ After the line is being implemented await sr.ReadToEndAsync()the continuation of the method GetFromFS() He'll be in the caste context. This is the first challenge. Post()♪ Next method GetFromFS() completion and continuation of the method GetBrowsers() It's back in the caste context. This is the second challenge. Post()♪ However, as the caste context simply starts the code in the pool of flows, these continuations are already in operation. in the context of the pool of flows♪ That is why we no longer see the challenges of the caste context.Method GetFromFS() Started in the flow with id=1. However, the continuation itself was carried out in flow with id=3 for the reason described above. Continuation after challenge GetFromFS() caused by the same flow (Post, thread id = 3)"The first one," like anyone else, is waiting for a special IO flow (i.e. IO completion port, IOCP). But these streams are waiting for a very large number of completions, so there's no need to talk about one casket, one waiting flow. I'm gonna go back and read the details. https://habrahabr.ru/post/216659/ ♪Continuation async of the method captured context. If there is no such context (e.g. challenge ConfigureAwait(false)() -- Continuation is carried out in the context of the pool of flows. Continuation in the relevant context is performed by the compiler -- it generates a call code Post()♪ The compiler selects the async method to the constituents (prologue + continuation) and generates the steroid machine with the transitions. I suggest you take a look. http://www.youtube.com/watch?v=lh8cT6qI-nA (or at least) http://andreycha.info/files/dotnext-msk-14/async-await_avoiding_common_mistakes-slides.pptx as well as https://ru.stackoverflow.com/a/491783/106 ♪ After this phrase like "async/await is changing the context," you've got to lose your rim.As a summary, you've had a disquieting result because your implementation of the context is, strictly speaking, incorrect. In fact, it is similar to the context of the pool of flows, which is used for consolidated applications and where all the continuations are carried out unless another context has been found.