Здравствуйте, я захотел опробовать такую вкусняшку C# как async/await и написал тестовую программу:
class MySynchronizationContext : SynchronizationContext
{
public override void Post(SendOrPostCallback d, object state)
{
Console.WriteLine("Post");
base.Post(d, state);
}
public override void Send(SendOrPostCallback d, object state)
{
Console.WriteLine("Send");
base.Send(d, state);
}
}
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()
{
var res = string.Empty;
var bd = await GetFromFS();
res += bd; // <-тут могла быть операция с UI
var net = await GetFromNet();
res += " and " + net; // <-тут могла быть операция с UI
var cpu = await Task.Run<string>(() => { Thread.Sleep(200); return "edge"; });
res += " and " + cpu; // <-тут могла быть операция с UI
return res;
}
static async Task<string> GetFromFS()
{
using (var sr = new StreamReader(@"C:\bd.txt"))
{
var res = await sr.ReadToEndAsync();
// тут могла быть операция с UI
return res + " and firefox";
}
}
static async Task<string> GetFromNet()
{
await Task.Delay(200);
// тут могла быть операция с UI
return "chrome";
}
}
Я ожидал, что после каждого await'а мой контекст будет восстанавливаться (ведь будь это приложение с UI, то надо же получать доступ к контролам), а значит, что после каждого await'а в консоль будет выводится "Post", но каково было мое удивление когда вывелся только 2 раза. Отсюда вопрос:
- почему контекст привязывается не всегда?
Теперь к async/await: как я понимаю, начиная с var browsers = GetBrowsers(); вызов будет проводится по стеку вниз до первого таска (в данном случае sr.ReadToEndAsync();, а может и ниже), и управление сразу перейдет обратно в метод Main(), не дожидаясь завершения этого таска; остальная часть async-методов будет выполняться после выполнения данного таска и так далее, из чего возникает следующий вопрос:
- кто ждет тот самый первый таск (затем следующие, когда до них дойдет
очередь после
await'а), изменяет его состояние наRanToCompletion? Думаю, было бы глупо думать, что для ожидания выделяется поток из пула потоков, да?
Третий вопрос стоит на стыке тасков и пула потоков. Продолжение после await, как я понимаю, выполняется в пуле потоков (там ему передается контекст), но...
- что засовывает часть кода после
awaitв пул потоков и когда (когда таск завершился или когда создался?)?
Заранее спасибо за прояснение ситуации