Asenkron Programlama – Async ve Await C#

Async ve Await, uygulamamızı asenkron olarak programlamamıza yardımcı olan iki anahtar kelimedir. Async anahtar sözcüğü, bir veri tabanından veri çekme, dosya okuma gibi asenkron (eş zamansız) görevleri gerçekleştiren bir metottur. Bunlar “async” olarak işaretlenebilir. Bir ifadeye “await” anahtar kelimesi yapmak, asenkron /eş zamansız) görev tamamlanana kadar içinde bulunduğu asenkron (eş zamansız) metodun yürütülmesini askıya almak anlamına gelir. Askıya alma işleminden sonra kontrol, çağıran metoda geri döner. Görev tamamlandıktan sonra kontrol, await’in belirtildiği durumlara geri döner ve onu çevreleyen metotta kalan ifadeleri yürütür.

Asenkron (Eş zamansız) ve bekleme operatörleri olan ve olmayan kodun davranışını görelim.

Senkron Programlama

Genel olarak, kod sırayla yürütülür, yani ifadeler birbiri ardına yürütülür. Diğer bir deyişle standart programlama deneyimi.

Aşağıdaki senkronize kodumuzda, kodun yürütme süresini kaydetmek için Kronometreyi kullanacağız. Bu metotların çalışmasının biraz zaman aldığını simüle etmek için Thread.Sleep(n)’nin belirtildiği üç metodumuz var.

Bu senaryomuzda bir okul örneğini ele alacağız normal bir hayatta bir okul ders zili çaldıktan sonra tüm sınıflar aynı anda eğitime başlar. Ancak senkron bir programlamada bunu uygulayamazsınız çünkü metotlarınız bir önce ki metottun görevini tamamlamasını bekler. Bu örneğimizde de doğal olarak önce okul başlayacak sonra 12 sınıflar eğitime başlayacak sonrasında ise 11 sınıflar.

internal class Program
{
    private static void Main(string[] args)
    {
        Demo();
    }

    public static void Demo()
    {
        var watch = new System.Diagnostics.Stopwatch();
        watch.Start();

        StartSchool();
        TeachClass12();
        TeachClass11();

        watch.Stop();
        Console.WriteLine($"Uygulama Vakti: { watch.ElapsedMilliseconds} ms");
    }

    public static void StartSchool()
    {
        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");

    }
}

Sonuç:

Okul Başladı
12. Sınıflar Derse Başladı
11. Sınıflar Derse Başladı
Uygulama Vakti: 13083 ms

Asenkron Programlama

Asenkron programlama kullanmak, bir metodun başka bir metodun tamamlanmasını beklemeden yürütülebileceğini gösterir. async ve wait kullanarak yukarıdaki metotları paralel olarak çalıştırabiliriz.

internal class Program
{
    private static void Main(string[] args)
    {
        Demo();
    }

    public static async void Demo()
    {
        var watch = new System.Diagnostics.Stopwatch();
        watch.Start();

        var task1 = StartSchool();
        var task2 = TeachClass12();
        var task3 = TeachClass11();
        Task.WaitAll(task1,task2,task3);

        watch.Stop();
        Console.WriteLine($"Uygulama Vakti: { watch.ElapsedMilliseconds} ms");
    }

    public static async Task StartSchool()
    {
        await Task.Run(() => 
        {
            Thread.Sleep(8000);
            Console.WriteLine("Okul Başladı");
        });
    }

    public static async Task TeachClass12()
    {
        await Task.Run(() => 
        {
            Thread.Sleep(3000);
            Console.WriteLine("12. Sınıflar Derse Başladı");
        });
    }

    public static async Task TeachClass11()
    {
        await Task.Run(() =>
        {
            Thread.Sleep(2000);
            Console.WriteLine("11. Sınıflar Derse Başladı");
        });
    }
}

Sonuç:

11. Sınıflar Derse Başladı
12. Sınıflar Derse Başladı
Okul Başladı
Uygulama Vakti: 8023 ms

Yukarıdaki tüm metotların paralel olarak çalıştığına ve yürütme süresinin en uzun süreyi alan metodun (StartSchool) süresi ile aynı olduğuna dikkat edin.

Peki bu çıktıyı gerçekten istiyor muyuz? Okul başlamadan 11. ve 12. sınıfları öğretmeye nasıl başlatabiliriz? O halde ne kadar sürerse sürsün okulu başlatan metodun bitmesini bekleyelim ve daha sonra 11. ve 12. sınıfların öğretimi aynı anda başlatalım.

Burada task1 okulun başlamasını temsil eder. Bu nedenle, okulun başlaması görevinin bitmesini beklemek için “await” anahtar sözcüğünü kullanalım.

internal class Program
{
    private static void Main(string[] args)
    {
        Demo();
        Console.ReadLine();
    }

    public static async void Demo()
    {
        var watch = new System.Diagnostics.Stopwatch();
        watch.Start();

        var task1 = StartSchool();
        await task1;
        var task2 = TeachClass12();
        var task3 = TeachClass11();
        Task.WaitAll(task1,task2,task3);

        watch.Stop();
        Console.WriteLine($"Uygulama Vakti: { watch.ElapsedMilliseconds} ms");
    }

    public static async Task StartSchool()
    {
        await Task.Run(() => 
        {
            Thread.Sleep(8000);
            Console.WriteLine("Okul Başladı");
        });
    }

    public static async Task TeachClass12()
    {
        await Task.Run(() => 
        {
            Thread.Sleep(3000);
            Console.WriteLine("12. Sınıflar Derse Başladı");
        });
    }

    public static async Task TeachClass11()
    {
        await Task.Run(() =>
        {
            Thread.Sleep(2000);
            Console.WriteLine("11. Sınıflar Derse Başladı");
        });
    }
}

Sonuç:

Okul Başladı
11. Sınıflar Derse Başladı
12. Sınıflar Derse Başladı
Uygulama Vakti: 11092 ms

Artık TeachClass12() ve TeachClass11()’in yalnızca StartSchool() metodu tamamlandıktan sonra çalıştırıldığına dikkat edin. StartSchol() metodun tamamlanması 8 saniye sürer. 11. Sınıf, sadece 2 saniye sürdüğü için dersi kısa sürede bitirir. 12. Sınıf 3 saniye sürdüğü için biraz daha geç bitiyor. Bu nedenle toplam yürütme süresi 8s + 3s = 11s’dir.