Асинхронность и ожидание в C#
Async и Await — это два ключевых слова, которые помогают нам программировать асинхронно. Ключевое слово async — это метод, который выполняет асинхронные задачи, такие как выборка данных из базы данных, чтение файла и т. д. Они могут быть помечены как «асинхронные». Принимая во внимание, что ключевое слово await делает «ожидание» оператора означает приостановку выполнения асинхронного метода, в котором он находится, до завершения асинхронной задачи. После приостановки управление возвращается вызывающему методу. После завершения задачи элемент управления возвращается в состояния, в которых упоминается ожидание, и выполняет оставшиеся операторы включающего метода.
Давайте посмотрим на поведение кода с операторами async и await и без них.
Синхронное программирование:
Как правило, код выполняется последовательно, т. е. операторы выполняются один за другим. Возьмем небольшой пример школы, в которой есть 11 и 12 классы.
- Первое, что делает школа, — это начинает собрание, которое может состоять из утренней молитвы, присяги, ежедневных обновлений и т. д.
- После собрания начинаются учения для 11 и 12 классов.
В нашем синхронном коде ниже мы будем использовать секундомер для записи времени выполнения кода. У нас есть три метода, в которых указан Thread.Sleep(n) для имитации того, что эти методы требуют некоторого времени для выполнения.
Пример 1:
C#
// C# program using System; using System.Threading; public class GFG{ static void Main( string [] args) { Demo(); Console.ReadLine(); } public static void Demo() { var watch = new System.Diagnostics.Stopwatch(); watch.Start(); StartSchoolAssembly(); TeachClass12(); TeachClass11(); watch.Stop(); Console.WriteLine($"Execution Time: {watch.ElapsedMilliseconds} ms"); } public static void StartSchoolAssembly() { Thread.Sleep(8000); Console.WriteLine( "School Started" ); } public static void TeachClass12() { Thread.Sleep(3000); Console.WriteLine( "Taught class 12" ); } public static void TeachClass11() { Thread.Sleep(2000); Console.WriteLine( "Taught class 11" ); } } |
Выход:
Асинхронное программирование:
Использование асинхронного программирования указывает на то, что метод может выполняться, не дожидаясь завершения другого метода. Используя async и await, мы можем запускать описанные выше методы параллельно.
Пример 2:
C#
// C# program for async and await using System; using System.Threading; using System.Threading.Tasks; public class GFG{ static void Main( string [] args) { Demo(); Console.ReadLine(); } public static void Demo() { var watch = new System.Diagnostics.Stopwatch(); watch.Start(); var task1 = StartSchoolAssembly(); var task2 = TeachClass12(); var task3 = TeachClass11(); Task.WaitAll(task1, task2, task3); watch.Stop(); Console.WriteLine($"Execution Time: {watch.ElapsedMilliseconds} ms"); } public static async Task StartSchoolAssembly() { await Task.Run(() => { Thread.Sleep(8000); Console.WriteLine( "School Started" ); }); } public static async Task TeachClass12() { await Task.Run(() => { Thread.Sleep(3000); Console.WriteLine( "Taught class 12" ); }); } public static async Task TeachClass11() { await Task.Run(() => { Thread.Sleep(2000); Console.WriteLine( "Taught class 11" ); }); } } |
Выход:
Обратите внимание, что эти вышеприведенные методы выполняются параллельно, и время выполнения будет таким же, как и время, затраченное StartSchoolAssembly(), поскольку этот метод занимает больше всего времени.
Нам действительно нужен этот результат? Как мы можем начать обучение в 11 и 12 классах, не начав школьного собрания? Давайте дождемся окончания школьного собрания, сколько бы времени оно ни заняло, а затем можно будет начать обучение в 11 и 12 классах.
Здесь task1 представляет школьную сборку. Поэтому давайте использовать ключевое слово await, чтобы дождаться завершения задачи школьной сборки.
Пример 3:
C#
// C# program for await keyword using System; using System.Threading; using System.Threading.Tasks; public class GFG { static void Main( string [] args) { Demo(); Console.ReadLine(); } public static async void Demo() { var watch = new System.Diagnostics.Stopwatch(); watch.Start(); var task1 = StartSchoolAssembly(); await task1; var task2 = TeachClass12(); var task3 = TeachClass11(); Task.WaitAll(task1, task2, task3); watch.Stop(); Console.WriteLine($"Execution Time: {watch.ElapsedMilliseconds} ms"); } public static async Task StartSchoolAssembly() { await Task.Run(() => { Thread.Sleep(8000); Console.WriteLine( "School Started" ); }); } public static async Task TeachClass12() { await Task.Run(() => { Thread.Sleep(3000); Console.WriteLine( "Taught class 12" ); }); } public static async Task TeachClass11() { await Task.Run(() => { Thread.Sleep(2000); Console.WriteLine( "Taught class 11" ); }); } } |
Выход:
Обратите внимание, что TeachClass12() и TeachClass11() выполняются только после завершения StartSchoolAssembly(). Сборка школы занимает 8 секунд. Класс 11 заканчивает урок быстро, так как это занимает всего 2 секунды. Класс 12 заканчивается немного позже, так как это занимает 3 секунды. Следовательно, общее время выполнения составляет 8 с + 3 с = 11 с.