У меня есть следующий код
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()», а затем отображается «Перед возвратом задачи».
Короче говоря, асинхронные методы, которые не выполняют никакой действительно асинхронной работы, работают так же, как и не асинхронные.
Я использую await с "Foo()" в методе "StartMyTask". Разве он не должен дождаться завершения Foo и вернуть управление обратно методу Main? @LasseVågsætherKarlsen
Да, должно, разве не так? Ваш вопрос, кажется, указывает на то, что он завершает весь вызов StartMyTask
, включая весь цикл, прежде чем "Before Task return"
будет напечатан.
Нет. Если он это делает, то «Before Task Return» должен быть напечатан перед выполнением Foo, но это не делает @LasseVågsætherKarlsen
Правильно, как вы сказали, он ожидает завершения Foo
, прежде чем он вернет управление обратно методу Main. Пожалуйста, проанализируйте то, что вы говорите, и будьте конкретны.
да, не следует ли печатать «Перед возвратом задачи» до полного выполнения Foo? @LasseVågsætherKarlsen
Нет, не так, как вы написали свой код. Как я уже сказал, ваше понимание async/await неверно. Ни одно из этих двух ключевых слов не создает новых тем. Поскольку здесь вы не выполняете фактически асинхронную работу, ваш код ведет себя точно так же, как если бы вы удалили ключевые слова async/await и сделали все синхронно.
Давайте продолжить обсуждение в чате.
Поскольку ваш Async ничего не ожидает, он будет работать синхронно. Вы должны получить предупреждение в компиляторе по этому поводу.
StartMyTask ждет в Foo @theMayer
Если вы напишете в своем методе StartMytask: await Task.Delay(100); await Foo();
вы получите желаемый результат :)
короткая версия: async != threads (это связанные темы, но не то же самое)
Поскольку ваш метод 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;
}
Я лихорадочно пытался ответить на этот вопрос раньше, чем Стивен Клири и Эрик Липпертс этого мира. Ну что ж.
Я ждал его ответа.
Когда вы говорите control goes back to caller
, не могли бы вы сказать мне, использует ли вызывающая сторона тот же поток для последующего выполнения кода, который использовался для вызова функции ожидания?
@переменная: Да. С точки зрения среды выполнения поток вызвал метод, который вернул задачу. Затем поток продолжает выполнение после возврата метода.
Тогда почему сказано, что поток возвращается в пул потоков при ожидании.
@variable: это упрощение. Поток пула потоков возвращается в пул потоков только на верхнем уровне await
.
Ваше понимание неверно, поток для
Foo
не создается, и, поскольку он на самом деле не выполняет никакой асинхронной работы, он будет блокироваться до тех пор, пока цикл не завершится.