Страницы

Поиск по вопросам

среда, 27 ноября 2019 г.

Как работают await async [дубликат]

#c_sharp #async_await #async_programming



    На данный вопрос уже ответили:
    
        
            Нужен async/await или не нужен?
                
                    5 ответов
                
        
    
    
Прочитал много литературы но пока никак не могу понять как работает await и async.
Ну хоть убейте. Везде примеры с httpclient, но для меня они не понятны. Пытаюсь разобраться сам.
Вот что я понял:


  Как только наш код встречает await
  происходит возврат управления. После
  завершения ожидаемой операции метод
  восстанавливается. Точнее продолжает
  выполнение с того места, на котором
  остановился, когда столкнулся с await.


Хорошо, я написал пару строк кода(возможно просто что-то сделал не так)

async Task myMethod() {
    int sum = 0;
    await SomeCycleAsync();
    Console.WriteLine("выполнился цикл2");
}
async Task SomeCycleAsync() {
    var myTask = await ResultOfCycle();

    Console.WriteLine("выполнился цикл1");
}
async Task < int > ResultOfCycle() {
    int sum = 0;
    for (int i = 0; i < 1000000000; i++) {
        sum += i;
    }
    return sum;
}

private void Form1_Load(object sender, EventArgs e) {
    myMethod();
}



В методе myMethod встречается слово await и, на сколько я понимаю, управление должна
перейти обратно в form_load, верно?
Во время выполнения метода SomeCycleAsync встречается await, т.е. по логике управление
должно перейти к Console.WriteLine("выполнился цикл2"); Но результат работы такой:



  выполнился цикл1
  
  выполнился цикл2


Объясните мне пожалуйста почему? Совсем не понимаю
    


Ответы

Ответ 1



Смотрите. Сами по себе async/await не включают таинственным образом многопоточность/асинхронность. Они лишь создают условия, при которых эту самую асинхронность легко реализовать. На самом деле, когда вызывается async-метод, происходит следующее. Начинает синхронно выполняться async-метод. Если этот метод заканчивается до первого await, результат доставляется синхронно, и из метода возвращается уже закончившийся, завершённый Task. Если в процессе выполнения встретился await, система проверяет, отработало ли уже задание, на которое вызывался await. Если это задание отработало, то подставляется его результат, и синхронное выполнение продолжается дальше. Если задание, на которое происходит await, ещё не отработало, в этот момент из метода возвращается незавершённый Task. В этой точке внешний код получает управление и продолжает выполняться. Например, этот код может записать Task в переменную и продолжать заниматься своими делами. Или он может выполнить await на полученный Task, и поскольку этот Task ещё не завершён, внешний код в этот момент аналогично отдаст управление ещё более внешнему коду, и. т. д. Когда Task, на который происходит await, завершится (произведя результат или исключение), код после await возобновит свою работу. В вашем случае происходит следующее: Вызывается Form1_Load. Выполняется строчка myMethod();. Этот код произведёт Task, который впоследствии будет просто проигнорирован. Начинает выполняться код метода myMethod. Выполняется синхронно int sum = 0;. Для выполнения следующей строчки для начала нужно выполнить метод SomeCycleAsync а затем await на результирующий Task. Начинается выполнение SomeCycleAsync. Для получения Task'а, по которому нужно делать await, запускается метод ResultOfCycle. Начинается выполнение ResultOfCycle(). Поскольку нигде в нём нету асинхронных вызовов, он выполняется полностью синхронно. Из метода возвращается завершённый Task. Управление возвращается в SomeCycleAsync. Выполняется await на Task, полученный в предыдущем пункте. Поскольку этот Task уже завершён, в переменную myTask просто записывается int-результат. Выполняется строчка Console.WriteLine("выполнился цикл1");. На этом выполнение метода SomeCycleAsync оканчивается. Поскольку в нём не было асинхронного ожидания, возвращается завершённый Task. Управление возвращается в метод myMethod(). Начинает выполняться await на полученный Task. Поскольку Task завершён, ничего не происходит, метод продолжает синхронно выполняться. Срабатывает строчка Console.WriteLine("выполнился цикл2");, метод заканчивается, возвращая завершённый Task. Управление возвращается в Form_Load. Полученный Task игнорируется, выполнение завершается. Для ваших целей правильнее было бы явно запускать вычисления асинхронным образом. Например, так: async Task myMethod() { await SomeCycleAsync(); Console.WriteLine("выполнился цикл-2"); } async Task SomeCycleAsync() { Console.WriteLine("стартует цикл"); // это запускает длинное вычисление на пуле потоков var result = await Task.Run(ResultOfCycle); Console.WriteLine("выполнился цикл, результат: " + result); } int ResultOfCycle() { int sum = 0; for (int i = 0; i < 1000000000; i++) sum += i; return sum; } private async void Form1_Load(object sender, EventArgs e) { await myMethod(); }

Ответ 2



У тебя ResultOfCycle() должна вернуть Task, но возвращает sum, которая является просто int. В самом методе нету второго потока, в котором он бы выполнялся. Await пишется перед объектом Task или методом, возвращающим объект Task. Пример для Task(вызов функции, которая ничего не возвращает): static void Main(string[] args) { My(); for (int i = 1; i <= 10; i++) { Thread.Sleep(1000); Console.WriteLine($"* {i*1000}"); } Console.ReadLine(); } static async void My() { await GetMessage(3000); } static Task GetMessage(int time) { return Task.Run(() => { Thread.Sleep(time); Console.WriteLine($"zxzxz {time.ToString()}"); }); } Пример для Task(вызов функции, которая возвращает объект типа T или в нашем случае string): static void Main(string[] args) { My(); for (int i = 1; i < 10; i++) { Thread.Sleep(1000); Console.WriteLine($"* {i*1000}"); } Console.ReadLine(); } static async void My() { string message = await GetMessage(3000); Console.WriteLine(message); } static Task GetMessage(int time) { return Task.Run(() => { Thread.Sleep(time); return $"zxzxz {time.ToString()}"; }); }

Комментариев нет:

Отправить комментарий