Altbilgi içeriğine atla
Iron Academy Logo
C# öğrenin
C# öğrenin

Diğer Kategoriler

C# Async ve Await'i Ustalaşmak

[[academy-video-youtube({"vid": "2moh18sh5p4", "start_time": "0", "title": "Mastering C# Async and Await", "creator": "Tim Corey", "length": "38m 57s"})]]

Asenkron programlama karmaşık terminolojisiyle bunaltıcı görünebilir, ancak uygulamaları daha hızlı ve daha duyarlı hale getirmekte önemli yararlar sağlar. Tim Corey'nin "C# Async / Await - Asenkron programlama ile uygulamanızı daha duyarlı ve daha hızlı hale getirin" videosu, bu özellikleri etkili bir şekilde kullanmak için pratik bir rehber sunmaktadır.

Bu makalede, Tim Corey'nin detaylı videosunu kullanarak bu kavramları çözümleyeceğiz, asenkron ve await'in pratik uygulamalarını net örneklerle göstereceğiz. Asenkron olay işleyicilerden, birden fazla görevin ele alınmasına, senkronizasyon bağlamlarına, hata yönetimine ve async void metotları kullanımındaki sık karşılaşılan tuzaklara kadar çeşitli senaryoları ele alacağız. Bu makalenin sonunda, asenkron programlama hakkında sağlam bir anlayışa sahip olacak ve bunu kendi C# uygulamalarınızda nasıl uygulayacağınızı öğreneceksiniz.

Giriş

C#'ta asenkron programlama, özellikle I/O bağımlı veya CPU bağımlı işlemlerle çalışırken, uygulama performansını artırmak için gereklidir. async ve await anahtar kelimeleri, geliştiricilere ana iş parçacığını engellemeden uzun süreli görevler çalıştırabilecekleri eşzamansız kod yazma olanağı sağlar. Bir yöntemi async anahtar kelimesiyle işaretleyerek, yöntemin eşzamansız bir işlem gerçekleştireceğini ve bir Task veya Task<t> döndüreceğini belirtirsiniz. Eşzamansız bir yöntem içinde await anahtar kelimesi kullanılarak, beklenen görev tamamlanana kadar yürütme durdurulur ve diğer işlemler eşzamanlı olarak çalışabilir.

Senkron programlamanın aksine, görevler ardışık olarak çalışır ve çağıran iş parçacığını engelleyebilir, asenkron metotlar ise arka plan süreçleri veya kullanıcı girdisi gibi birden çok görevi aynı anda gerçekleştirebilmenizi sağlar; bu da kullanıcı arayüzü iş parçacığını donmadan ele alır. Bu makalede, async ve await'ın nasıl birlikte çalıştığını, eşzamansız void yöntemleri, hata yönetimi, bağlam değişimleri ve senkronizasyon bağlamları gibi kavramları ele alacağız. Çoklu asenkron işlemleri verimli bir şekilde yönetmeyi ve istisnaları ele almayı öğrenecek, böylece çağıran iş parçacığı, kullanıcı arayüzü iş parçacığı ve görev tamamlanması boyunca sorunsuz bir yürütme sağlayacaksınız. Bu yaklaşım, dosya sistemleri, ağ istekleri veya eşzamanlı istekler içeren durumlar için özellikle yararlıdır; burada duyarlılık anahtardır.

Tim, asenkron programlamayı, senkron ve asenkron işlemler arasındaki farkı açıklayarak tanıtır. Senkron programlamada, görevler ardışık olarak gerçekleştirilir, bir görev uzun süre alıyorsa gecikmelere neden olabilir. Asenkron programlama ise görevlerin paralel veya arka planda yürütülmesine izin vererek, performansı ve duyarlılığı artırır.

Asenkron Programlamanın Faydaları

Tim, asenkron programlamanın iki ana faydasını vurgular:

  1. Gelişmiş Kullanıcı Arayüzü (UI) Duyarlılığı: Görevleri asenkron gerçekleştiren UI, uzun süren işlemler sırasında bile duyarlı kalır.

  2. Paralel Yürütme: Bağımsız görevler paralel olarak yürütülerek tamamlanması gereken toplam süreyi azaltır.

Demo Uygulama Gezintisi

Tim, senkron ve asenkron işlemler arasındaki farkı göstermek için bir demo Windows Sunum Temeli (WPF) uygulaması kurar. Uygulamada görevleri senkron ve asenkron olarak yürüten iki düğme vardır.

Demo Uygulaması

Uygulama ayrıca çıktıyı göstermek için sonuçlar paneli içerir.

Senkron İşlem

Tim, senkron işlemin arkasındaki kodu açıklar. Bir görevin yürütme zamanını ölçmek için Stopwatch kullanılır.

private void ExecuteSync_Click(object sender, RoutedEventArgs e)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    List<string> websites = GetWebsiteList();
    foreach (var website in websites)
    {
        string result = DownloadWebsite(website);
        ReportWebsiteInfo(website, result);
    }
    stopwatch.Stop();
    ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}

private List<string> GetWebsiteList()
{
    return new List<string>
    {
        "https://www.yahoo.com",
        "https://www.google.com",
        "https://www.microsoft.com",
        "https://www.cnn.com",
        "https://www.codeproject.com",
        "https://www.stackoverflow.com"
    };
}

private string DownloadWebsite(string websiteURL)
{
    WebClient client = new WebClient();
    return client.DownloadString(websiteURL);
}

private void ReportWebsiteInfo(string website, string data)
{
    ResultsWindow.Text += $"{website}: {data.Length} characters{Environment.NewLine}";
}
private void ExecuteSync_Click(object sender, RoutedEventArgs e)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    List<string> websites = GetWebsiteList();
    foreach (var website in websites)
    {
        string result = DownloadWebsite(website);
        ReportWebsiteInfo(website, result);
    }
    stopwatch.Stop();
    ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}

private List<string> GetWebsiteList()
{
    return new List<string>
    {
        "https://www.yahoo.com",
        "https://www.google.com",
        "https://www.microsoft.com",
        "https://www.cnn.com",
        "https://www.codeproject.com",
        "https://www.stackoverflow.com"
    };
}

private string DownloadWebsite(string websiteURL)
{
    WebClient client = new WebClient();
    return client.DownloadString(websiteURL);
}

private void ReportWebsiteInfo(string website, string data)
{
    ResultsWindow.Text += $"{website}: {data.Length} characters{Environment.NewLine}";
}

Bu kod, aşağıdaki adımları gerçekleştirir:

  1. Kronometreyi Başlat: Yürütme süresini ölçer.
  2. Web Sitesi Listesini Al: Web sitesi URL'lerinin bir listesini alır.
  3. Her Web Sitesini İndir: Her web sitesinin içeriğini indirir.
  4. Web Sitesi Bilgilerini Rapor Et: URL'yi ve indirilen içeriğin uzunluğunu görüntüler.
  5. Kronometreyi Durdur: Zamanlayıcıyı durdurur ve toplam yürütme süresini rapor eder.

Senkron İşlemi Gözlemleme

Tim, senkron işlemi göstermek için uygulamayı çalıştırır. İnternet siteleri indirilirken kullanıcı arayüzünün tepkisiz hale geldiğini ve sonuçların indirmeler tamamlandıktan sonra birden gösterildiğini belirtir.

Senkron İşlem

Formun hareket etmediğinin pratik bir gösterimi için videoyu 9:20'de izleyin.

Bir Asenkron Görev Oluşturma

Tim, senkron metodu asenkron hale dönüştürerek ilk sorunu ele alır. Bu, async ve await anahtar kelimelerinin kullanılmasıyla ilgilidir. İşte sürecin adım adım açıklaması:

  1. Mevcut Senkron Metodu Kopyala:

    • Tim, mevcut senkron metodu kopyalar ve asenkron olacağını göstermek için adını değiştirir.
    private async Task RunDownloadAsync()
    {
       // Same code as RunDownloadSync, but will be modified for async
    }
    private async Task RunDownloadAsync()
    {
       // Same code as RunDownloadSync, but will be modified for async
    }
  2. İndirme Çağrısını Asenkron Yürütme için Değiştir:

    • Tim, indirme çağrısını eşzamansız olarak yürütmek için Task.Run içinde sarar.
    private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
    {
       return await Task.Run(() => DownloadWebsite(websiteURL));
    }
    private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
    {
       return await Task.Run(() => DownloadWebsite(websiteURL));
    }
    • await anahtar kelimesi, eşzamansız görev tamamlanana kadar yöntemin beklediğinden emin olur.
  3. Metodun Asenkron Olduğundan Emin Ol:

    • Yöntem imzası async anahtar kelimesini içerecek şekilde güncellenir ve bir Task döndürür.
    private async Task RunDownloadAsync()
    {
       List<string> websites = GetWebsiteList();
       foreach (var website in websites)
       {
           var result = await DownloadWebsiteAsync(website);
           ReportWebsiteInfo(website, result);
       }
    }
    private async Task RunDownloadAsync()
    {
       List<string> websites = GetWebsiteList();
       foreach (var website in websites)
       {
           var result = await DownloadWebsiteAsync(website);
           ReportWebsiteInfo(website, result);
       }
    }
  4. Olayı Doğru Şekilde Yönet:

    • Düğme tıklama olay işleyicisi, yeni asenkron metodu çağıracak şekilde güncellenir.
    private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
    {
       Stopwatch stopwatch = Stopwatch.StartNew();
       await RunDownloadAsync();
       stopwatch.Stop();
       ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
    }
    private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
    {
       Stopwatch stopwatch = Stopwatch.StartNew();
       await RunDownloadAsync();
       stopwatch.Stop();
       ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
    }
    • Olay işleyicilerinin asenkron metotlar çağırmasına rağmen void döndürebileceğini unutmayın.

UI Duyarlılığını Düzeltmek

Tim, await anahtar kelimesini kullanarak, UI'nin duyarlı kalmasını sağladığını gösterir. Bu, kullanıcıların eşzamansız görev çalışırken pencere ile etkileşim kurmalarını sağlar.

// UI remains responsive
private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    await RunDownloadAsync();
    stopwatch.Stop();
    ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}
// UI remains responsive
private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    await RunDownloadAsync();
    stopwatch.Stop();
    ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}

Doğru Zamanlamayı Sağlama

Toplam yürütme zamanının doğru bir şekilde raporlandığından emin olmak için Tim, düğme tıklama olay işleyicisi içindeki çağrıya await anahtar kelimesini ekler.

// Correctly waits for the asynchronous task to complete
private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    await RunDownloadAsync();
    stopwatch.Stop();
    ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}
// Correctly waits for the asynchronous task to complete
private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    await RunDownloadAsync();
    stopwatch.Stop();
    ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}

Asenkron metodun tamamlanmasını bekleyerek, yürütme süresi doğru bir şekilde ölçülür ve sonuclar geri alınırken gösterilir.

Paralel Asenkron Oluşturma

Tim, her görevin sırasıyla tamamlanmasını beklemenin sınırlandırmasını ele alarak paralel yürütmeyi kullanır. Bunu başarmak için kodu nasıl değiştirdiğine dair bazı adımlar:

  1. Mevcut Asenkron Metodu Kopyalama:

    • Tim, mevcut asenkron metodunu çoğaltır ve paralel yürütmeyi göstermek için adını değiştirir.
    private async Task RunDownloadParallelAsync()
    {
       // Parallel execution logic will be added here
    }
    private async Task RunDownloadParallelAsync()
    {
       // Parallel execution logic will be added here
    }
  2. Görevlerin Listesini Oluşturma:

    • Tüm indirme görevlerini saklamak için bir görev listesi oluşturulur.
    List<Task<WebsiteDataModel>> tasks = new List<Task<WebsiteDataModel>>();
    List<Task<WebsiteDataModel>> tasks = new List<Task<WebsiteDataModel>>();
  3. Bütün Görevleri Beklemeden Başlatma:

    • Her indirme görevini hemen beklemeye almak yerine, Tim onları görev listesine ekler.
    foreach (var website in websites)
    {
       tasks.Add(DownloadWebsiteAsync(website));
    }
    foreach (var website in websites)
    {
       tasks.Add(DownloadWebsiteAsync(website));
    }
  4. Tüm Görevlerin Tamamlanmasını Bekleme:

    • Task.WhenAll yöntemi, tüm görevlerin tamamlanmasını beklemek için kullanılır. Bu metod, tüm görevler tamamlandığında sonuçların bir dizisini döndürür.
    WebsiteDataModel[] results = await Task.WhenAll(tasks);
    WebsiteDataModel[] results = await Task.WhenAll(tasks);
  5. Sonuçları İşleme:

    • Tüm görevler tamamlandıktan sonra, Tim sonuçları döngü içinde işler.
    foreach (var result in results)
    {
       ReportWebsiteInfo(result);
    }
    foreach (var result in results)
    {
       ReportWebsiteInfo(result);
    }

Paralel yürütme metodu için tam kod burada:

private async Task RunDownloadParallelAsync()
{
    List<string> websites = GetWebsiteList();
    List<Task<WebsiteDataModel>> tasks = new List<Task<WebsiteDataModel>>();

    foreach (var website in websites)
    {
        tasks.Add(DownloadWebsiteAsync(website));
    }

    WebsiteDataModel[] results = await Task.WhenAll(tasks);

    foreach (var result in results)
    {
        ReportWebsiteInfo(result);
    }
}
private async Task RunDownloadParallelAsync()
{
    List<string> websites = GetWebsiteList();
    List<Task<WebsiteDataModel>> tasks = new List<Task<WebsiteDataModel>>();

    foreach (var website in websites)
    {
        tasks.Add(DownloadWebsiteAsync(website));
    }

    WebsiteDataModel[] results = await Task.WhenAll(tasks);

    foreach (var result in results)
    {
        ReportWebsiteInfo(result);
    }
}

Olay İşleyicisini Güncelleme

Tim, düğme tıklama olay işleyicisini, yeni paralel yürütme metodunu çağıracak şekilde günceller.

private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    await RunDownloadParallelAsync();
    stopwatch.Stop();
    ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}
private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    await RunDownloadParallelAsync();
    stopwatch.Stop();
    ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}

RunDownloadParallelAsync bekleyerek, toplam yürütme süresi doğru bir şekilde ölçülür ve rapor edilir.

Performans İyileştirmesini Gözlemleme

Tim, paralel yürütmeyi kullanarak uygulamayı çalıştırarak performans iyileştirmesini gösterir. Sonuçlar, toplam yürütme süresinde sıralı yürütmeye kıyasla önemli bir azalma göstermektedir.

// Parallel execution
async Task RunDownloadParallelAsync();
// Parallel execution
async Task RunDownloadParallelAsync();

Hız artışı, internet sitelerinin eşzamanlı olarak indirildiği için toplam bekleme süresinin en yavaş bireysel indirme süresine indirgenmesi ile belirgindir.

Task.Run() Yöntemi Sarma vs Eşzamansız Yöntem Çağrısı

Tim, orijinal yöntemi değiştiremeyeceğiniz durumlarda eşzamansız hale getirmek için bir senkronize yöntemi sarma kavramını Task.Run() kullanarak açıklar. Ancak, metodu kontrol edebiliyorsanız, metodu doğrudan asenkron hale getirmenin tercih edilen yaklaşım olduğunu da gösterir.

  1. Task.Run() Yöntemini Sarma:

    • Bu yöntem, orijinal metot kodunu değiştiremediğinizde ama yine de onu asenkron olarak yürütmek istediğinizde yararlıdır.
    private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
    {
       return await Task.Run(() => DownloadWebsite(websiteURL));
    }
    private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
    {
       return await Task.Run(() => DownloadWebsite(websiteURL));
    }
  2. Bir Metodu Asenkron Yapma:

    • Eğer metodu değiştirme şansınız varsa, onu asenkron hale getirmek için uygun bir asenkron API kullanarak metodu dönüştürmek daha iyidir.

    • Tim, DownloadWebsite'u DownloadWebsiteAsync şeklinde değiştirerek ve WebClient'dan DownloadStringTaskAsync kullanarak bunu gösterir.
    private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
    {
       WebClient client = new WebClient();
       string data = await client.DownloadStringTaskAsync(websiteURL);
    
       return new WebsiteDataModel { URL = websiteURL, Data = data };
    }
    private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
    {
       WebClient client = new WebClient();
       string data = await client.DownloadStringTaskAsync(websiteURL);
    
       return new WebsiteDataModel { URL = websiteURL, Data = data };
    }
  3. Çağıran Metodu Ayarlama:

    • Yöntemi dönüştürdükten sonra, çağrı kodu Task.Run() sarmalayıcıyı kaldırarak ve doğrudan eşzamansız yöntemi çağırarak ayarlanmalıdır.
    private async Task RunDownloadParallelAsync()
    {
       List<string> websites = GetWebsiteList();
       List<Task<WebsiteDataModel>> tasks = new List<Task<WebsiteDataModel>>();
    
       foreach (var website in websites)
       {
           tasks.Add(DownloadWebsiteAsync(website));
       }
    
       WebsiteDataModel[] results = await Task.WhenAll(tasks);
    
       foreach (var result in results)
       {
           ReportWebsiteInfo(result);
       }
    }
    private async Task RunDownloadParallelAsync()
    {
       List<string> websites = GetWebsiteList();
       List<Task<WebsiteDataModel>> tasks = new List<Task<WebsiteDataModel>>();
    
       foreach (var website in websites)
       {
           tasks.Add(DownloadWebsiteAsync(website));
       }
    
       WebsiteDataModel[] results = await Task.WhenAll(tasks);
    
       foreach (var result in results)
       {
           ReportWebsiteInfo(result);
       }
    }

Ana Noktaların Özeti

Tim, async ve await kullanımı için birkaç önemli çıkarımla konuyu tamamlar:

  • Görev Döndüren Yöntemleri Sağlama: Bir yöntemi async olarak işaretlediğinizde, void yerine bir Task veya Task<t> döndürmelidir (olay işleyicileri hariç).

  • Güvenilir İşlemler İçin await Kullanın: Eşzamansız bir işlemin sonucuna ihtiyaç duyduğunuzda await anahtar kelimesini kullanın.

  • Değiştirilemeyen Kod İçin Görev Sarma: Orijinal yöntemi değiştiremediğinizde senkronize yöntemleri sarmak için Task.Run() kullanın.

  • Eşzamansız Yöntemleri Uygun Şekilde İşaretleyin: Yöntemin eşzamansız bir işlem olduğunu göstermek için her zaman yöntemin adının sonuna Async ekleyin.

  • Paralel ve Ardışık Yürütme: Görevlerin paralel olarak yürütülüp yürütülemeyeceğini ya da her biri bekleme gerektirip gerektirmediğine, görevler arasındaki bağımlılıklar temelinde karar verin.

Tim, C# dilinde eşzamansız programlamanın async, await ve Task ile daha da basitleştirildiğini vurgular. İşlem bağlamları ve daire modelleri gibi karmaşıklıklar sahne arkasında yönetilmektedir.

Sonuç

Tim Corey'nin C#'ta async ve await dersliği, asenkron programlamayı öğrenmek için değerli bir kaynaktır. Görev paralelliği, kullanıcı arayüzü duyarlılığı ve doğru bağlamda async ve await'in kullanılmasının önemi gibi kavramları dikkatlice açıklayarak, Tim geliştiricilere daha hızlı ve daha duyarlı uygulama yaratma yeteneği sağlar. Uzun soluklu görevleri, ana iş parçacığını engellemeden verimli bir şekilde nasıl ele alacağınızı göstermenin yanı sıra, asenkron işlemleri ve paralel yürütmeyi yönetme stratejilerini detaylı bir yürütümle gösterir.

Daha derin bir anlayış ve ek pratik örnekler için, Tim Corey'nin videosunu izlemeni şiddetle öneririm. Async void metodlar, hata yönetimi ve senkronizasyon bağlamlarının yönetimi hakkında anlayışlarınız, bu kavramları projelerinize uygulama yeteneğinizi daha da geliştirecektir.

Hero Worlddot related to C# Async ve Await'i Ustalaşmak
Hero Affiliate related to C# Async ve Await'i Ustalaşmak

Sevdiğiniz Şeyleri Paylaşarak Daha Fazla Kazanın

.NET, C#, Java, Python veya Node.js ile çalışan geliştiriciler için içerik oluşturuyor musunuz? Uzmanlığınızı ek gelire dönüştürün!

Iron Destek Ekibi

Haftada 5 gün, 24 saat çevrimiçiyiz.
Sohbet
E-posta
Beni Ara