Mail.ruПочтаМой МирОдноклассникиВКонтактеИгрыЗнакомстваНовостиКалендарьОблакоЗаметкиВсе проекты

Асинхронные методы в c#

iweywey weywey Ученик (131), на голосовании 4 месяца назад
Изучал асинхронное программирование и автор привел такой пример:

await PrintAsync(); // вызов асинхронного метода
Console.WriteLine("Некоторые действия в методе Main");

void Print()
{
Thread.Sleep(3000); // имитация продолжительной работы
Console.WriteLine("не дает отправить анти-спам система");
}

// определение асинхронного метода
async Task PrintAsync()
{
Console.WriteLine("Начало метода PrintAsync"); // выполняется синхронно
await Task.Run (() => Print()); // выполняется асинхронно
Console.WriteLine("Конец метода PrintAsync");
}

и дал обьяснение:

1 Запускается программа, а точнее метод Main, в котором вызывается асинхронный метод PrintAsync.

2 Метод PrintAsync начинает выполняться синхронно вплоть до выражения await.


Console.WriteLine("Начало метода PrintAsync"); // выполняется синхронно
3 Выражение await запускает асинхронную задачу Task.Run (()=>Print())

4 Пока выполняется асинхронная задача Task.Run (()=>Print()) (а она может выполняться довольно продожительное время), выполнение кода возвращается в вызывающий метод - то есть в метод Main.

5 Когда асинхронная задача завершила свое выполнение (в случае выше - вывела строку через три секунды), продолжает работу асинхронный метод PrintAsync, который вызвал асинхронную задачу.

6 После завершения метода PrintAsync продолжает работу метод Main.

И показал результат:

Начало метода PrintAsync
( не дает отправить анти-спам система)
Конец метода PrintAsync
Некоторые действия в методе Main

Вопрос у меня вызвал четвертый пункт обьяснения - тоесть пока выполняется асинхронная операция , то действия в методе Main продолжат работу. Но в выводе они выполнились после выполнения асинхронного метода.
Как правильно понять слова автора "Пока выполняется асинхронная задача Task.Run(()=>Print()) (а она может выполняться довольно продожительное время), выполнение кода возвращается в вызывающий метод - то есть в метод Main. " ?
Голосование за лучший ответ
Бинарный Балагур Гений (84518) 5 месяцев назад
Вы правильно заметили несоответствие между объяснением автора и результатом выполнения кода. Давайте разберемся, что происходит на самом деле.

Когда вы вызываете асинхронный метод с помощью `await`, происходит следующее:

1. Выполнение кода в методе `PrintAsync` продолжается до выражения `await`.

2. При достижении `await`, управление возвращается в вызывающий контекст (в данном случае в метод `Main`), но не сразу продолжается выполнение кода в `Main`. Вместо этого, текущая синхронизация контекста (в данном случае контекст потока UI) сохраняется и будет использована для возобновления выполнения `PrintAsync` после завершения асинхронной операции.

3. Асинхронная операция (` Task.Run (() => Print())`) запускается в отдельном потоке.

4. Поскольку в данном случае асинхронная операция выполняется мгновенно (метод `Print` просто выводит сообщение после задержки), управление сразу же возвращается в `PrintAsync`, и выполнение продолжается до конца метода.

5. Когда `PrintAsync` завершается, управление возвращается в `Main`, и выполняется оставшаяся часть кода в `Main`.

Таким образом, в вашем примере, несмотря на то, что `Main` получает управление раньше, чем завершается асинхронная операция, вывод сообщения из `Print` происходит после завершения `PrintAsync`, так как `Print` выполняется в отдельном потоке.

Чтобы увидеть, как `Main` продолжает выполняться параллельно с асинхронной операцией, вы можете добавить дополнительные действия в `Main`, которые будут выполняться после вызова `await PrintAsync()`. Например:

```csharp
async Task Main()
{
await PrintAsync();
Console.WriteLine("Некоторые действия в методе Main");
Console.WriteLine("Дополнительные действия в методе Main");
}
```

В этом случае вывод будет следующим:

```
Начало метода PrintAsync
Конец метода PrintAsync
Некоторые действия в методе Main
Дополнительные действия в методе Main
(не дает отправить анти-спам система)
```

Как видите, действия в `Main` выполняются после `await PrintAsync()`, но до завершения асинхронной операции в `Print`.
PMC MAIL.RU Мастер (2290) 5 месяцев назад
Выглядит очень тяжело и страшно
iweywey weyweyУченик (131) 5 месяцев назад
вкратце - почему выполнение кода возвращается в вызывающий метод но при этом действия происходят после выполнения асинхронного метода ?
Милана Просветленный (33039) 5 месяцев назад
Давайте разберем шаги выполнения программы детально, чтобы понять, что происходит на каждом этапе.

1. **Запуск программы**: Метод `Main` вызывается первым. Первый выполняемый оператор — это вызов асинхронного метода `PrintAsync`.

2. **Начало выполнения `PrintAsync`**: Метод `PrintAsync` начинает свое выполнение синхронно до первого оператора `await`. Следовательно, сначала будет выполнена строка `Console.WriteLine("Начало метода PrintAsync");`.

3. **Асинхронный вызов с `await`**: Когда выполнение доходит до строки `await Task.Run(() => Print())`, начинается асинхронная обработка. Метод `Task.Run` запускает метод `Print` в отдельном потоке. Это означает, что основному потоку не нужно ждать завершения `Print`, а может продолжить выполнение других операций.

4. **Возврат в метод `Main`**: Пока выполняется асинхронный метод `Print`, поток, выполняющий `Main`, не блокируется и может продолжать выполнение. Но в данном примере следующий оператор после вызова `PrintAsync` — это `Console.WriteLine("Некоторые действия в методе Main")`.

5. **Когда асинхронная задача завершается**: После завершения метода `Print`, выполнение продолжается с точки, на которой было приостановлено в методе `PrintAsync`. Следовательно, будет выполнена строка `Console.WriteLine("Конец метода PrintAsync");`.

Шаги выполнения программы с учетом вышеупомянутого:

- **Начало метода PrintAsync**: Эта строка выводится первой.
- Асинхронный запуск метода `Print`, который задерживает выполнение на 3 секунды и выводит строку **не дает отправить анти-спам система**.
- Параллельно основного потока, выполнение возвращается в `Main`, но в вашем случае это автоматически ожидается выполнения вызова `PrintAsync`, поэтому строка **Некоторые действия в методе Main** выводится после завершения `PrintAsync`.
- **Конец метода PrintAsync**: Эта строка выводится после завершения асинхронной работы.

Вот частичное недоразумение: основной поток действительно возвращается в `Main`, но если вы ожидаете выполнение `PrintAsync`, он будет ждать завершения асинхронного выполнения перед продолжением.

Если вы хотите, чтобы строка **Некоторые действия в методе Main** действительно выполнялась параллельно с асинхронной задачей, вам нужно использовать `Task` и `await` грамотно.

Например, чтобы увидеть интерлейс этих операций:
```csharp
var printTask = PrintAsync(); // Не ожидаем окончания
Console.WriteLine("Некоторые действия в методе Main");
await printTask; // Ожидание завершения PrintAsync на конец выполнения
```

Таким образом, "пока выполняется асинхронная операция, выполнение кода возвращается в вызывающий метод" означает, что основной поток не блокируется вызовом `await`, а продолжает выполнение других операций в методе `Main`. В вашем конкретном случае выполнение оператора `Console.WriteLine("Некоторые действия в методе Main")` было отложено, пока не завершится вызов `PrintAsync`.
iweywey weyweyУченик (131) 5 месяцев назад
зачем ты мне ответ чат гпт отправляешь, ты думаешь я у него не спрашивал?
Jurijus Zaksas Искусственный Интеллект (445776) 5 месяцев назад
Наврал твой автор. Await синхронизирует таски. Чтобы все выполнялось параллельно, надо запускать Task.Run и не ждать его, а ехать дальше. А когда захочешь с ним синхронизироваться - вот тогда и подождать. Я, если честно, не очень понимаю, нафига все пишут эту якобы асинхронную фигню - в большинстве случаев она не работает, только тратит ресурсы системы на запуск новых потоков.

Вот пример параллельного кода, который работает:

 static void Main(string[] args) 
{
var MyTask = Task.Run(() =>
{
for (int i = 0;i < 5; i++)
{
Console.WriteLine($"Task iteration {i}");
Thread.Sleep(1000);
}
}
);
for (int i = 0; i < 5; i++)
{
Thread.Sleep(500);
Console.WriteLine($"Main job iteration {i}");
}
Task.WaitAll(MyTask);
Console.WriteLine("Finished.");
}
Похожие вопросы