Асинхронный метод не возвращает управление вызывающему методу

У меня есть следующий код

class Program
{
    public  async  Task<bool> StartMyTask()
    {
        await Foo();

        return true;

    }

    public async Task<bool> Foo()
    {

        for (int i = 0; i < 1000000; i++)
        {
            Console.WriteLine("Loop");
        }
        return true;

    }


    static void Main(string[] args)
    {
        Program obj = new Program();

        var myTask = obj.StartMyTask();     
        Console.WriteLine("Before Task Return");                                    


        Console.ReadLine();
    }
}

Насколько я понимаю, при вызове «await Foo()» будет создан поток, который выполнит метод «Foo()», и управление будет возвращено вызывающей стороне (метод Main).

Учитывая это, «Before Task Return» должен быть напечатан до завершения метода «Foo()». Но этого не происходит, сначала завершается метод «Foo()», а затем отображается «Перед возвратом задачи».

Ваше понимание неверно, поток для Foo не создается, и, поскольку он на самом деле не выполняет никакой асинхронной работы, он будет блокироваться до тех пор, пока цикл не завершится.

Lasse V. Karlsen 14.06.2019 13:42

Короче говоря, асинхронные методы, которые не выполняют никакой действительно асинхронной работы, работают так же, как и не асинхронные.

Sat 14.06.2019 13:45

Я использую await с "Foo()" в методе "StartMyTask". Разве он не должен дождаться завершения Foo и вернуть управление обратно методу Main? @LasseVågsætherKarlsen

Waleed Naveed 14.06.2019 13:46

Да, должно, разве не так? Ваш вопрос, кажется, указывает на то, что он завершает весь вызов StartMyTask, включая весь цикл, прежде чем "Before Task return" будет напечатан.

Lasse V. Karlsen 14.06.2019 13:47

Нет. Если он это делает, то «Before Task Return» должен быть напечатан перед выполнением Foo, но это не делает @LasseVågsætherKarlsen

Waleed Naveed 14.06.2019 13:48

Правильно, как вы сказали, он ожидает завершения Foo, прежде чем он вернет управление обратно методу Main. Пожалуйста, проанализируйте то, что вы говорите, и будьте конкретны.

Lasse V. Karlsen 14.06.2019 13:49

да, не следует ли печатать «Перед возвратом задачи» до полного выполнения Foo? @LasseVågsætherKarlsen

Waleed Naveed 14.06.2019 13:49

Нет, не так, как вы написали свой код. Как я уже сказал, ваше понимание async/await неверно. Ни одно из этих двух ключевых слов не создает новых тем. Поскольку здесь вы не выполняете фактически асинхронную работу, ваш код ведет себя точно так же, как если бы вы удалили ключевые слова async/await и сделали все синхронно.

Lasse V. Karlsen 14.06.2019 13:50

Давайте продолжить обсуждение в чате.

Lasse V. Karlsen 14.06.2019 13:51

Поскольку ваш Async ничего не ожидает, он будет работать синхронно. Вы должны получить предупреждение в компиляторе по этому поводу.

theMayer 14.06.2019 13:51

StartMyTask ждет в Foo @theMayer

Waleed Naveed 14.06.2019 13:58

Если вы напишете в своем методе StartMytask: await Task.Delay(100); await Foo(); вы получите желаемый результат :)

Maksim Simkin 14.06.2019 14:01

короткая версия: async != threads (это связанные темы, но не то же самое)

Marc Gravell 14.06.2019 14:03
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
13
874
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Поскольку ваш метод Foo не создает задачи, ваш код не будет расходиться, как вы ожидаете, но его выполнение следующим образом решает ваши проблемы:

public async Task<bool> Foo()
    {
       return await Task.Run(() =>
       {
           for (int i = 0; i < 100000; i++)
           {
               Console.WriteLine("Loop");
           }
           return true;
       });
    }
Ответ принят как подходящий

According to my understanding when "await Foo()" gets called, a thread will be created which will execute the "Foo()" method and the control would be returned back to the caller (Main method).

Нет, абсолютно нет. async и await не создают темы сами по себе. async позволяет вам использовать await, а await будет «асинхронно ждать» — т. е. приостанавливать метод, возвращаться, а затем возобновлять метод после завершения его операции..

Обратите внимание, что компилятор выдает вам предупреждение о том, что у вас есть метод, отмеченный async, но он будет работать синхронно. Таким образом, компилятор уже говорит вам, что именно не так.

Если вы хочу используете фоновый поток, вы можете использовать Task.Run для вызова синхронного Foo метода:

public async Task<bool> StartMyTask()
{
  await Task.Run(() => Foo());
  return true;
}

public bool Foo()
{
  for (int i = 0; i < 1000000; i++)
  {
    Console.WriteLine("Loop");
  }
  return true;
}

Я лихорадочно пытался ответить на этот вопрос раньше, чем Стивен Клири и Эрик Липпертс этого мира. Ну что ж.

Justin Blakley 14.06.2019 15:21

Я ждал его ответа.

Scott Hannen 14.06.2019 16:57

Когда вы говорите control goes back to caller, не могли бы вы сказать мне, использует ли вызывающая сторона тот же поток для последующего выполнения кода, который использовался для вызова функции ожидания?

variable 20.08.2021 19:57

@переменная: Да. С точки зрения среды выполнения поток вызвал метод, который вернул задачу. Затем поток продолжает выполнение после возврата метода.

Stephen Cleary 20.08.2021 22:54

Тогда почему сказано, что поток возвращается в пул потоков при ожидании.

variable 21.08.2021 03:32

@variable: это упрощение. Поток пула потоков возвращается в пул потоков только на верхнем уровне await.

Stephen Cleary 21.08.2021 04:33

Другие вопросы по теме