Асинхронность и ожидание в C#

Опубликовано: 9 Января, 2023

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 с.

C#