CodeGym /Kurslar /C# SELF /Açar sözlər async və ...

Açar sözlər asyncawait

C# SELF
Səviyyə , Dərs
Mövcuddur

1. Giriş

Koda tullanmazdan əvvəl motivasiyaya baxaq və tipik situasiyanı təsəvvür edək. Tutaq ki, proqramınız internetdən fayl yükləyir:

// Peyzaj kod
var data = DownloadFile("https://example.com/file");
ProcessData(data);

Problem budur: yükləmə gedən vaxt proqram "donur". Heç bir başqa əməliyyat yerinə yetirilmir — istifadəçi siçanı hərəkət etdirə, düymələrə klikləyə bilməz, ya da bitməsini səbirsizliklə gözləyə bilməz.

Əvvəllər (və digər dillərdə) bu problemi həll etmək üçün thread-lər (Thread), task-lar (Task), delegatlar, timer-lər istifadə olunurdu — bütün bunlar kodun çox dolaşıq olmasına, oxunmasının və saxlanmasının çətinləşməsinə gətirib çıxarırdı. C# komandası həyatımızı asanlaşdırmaq qərarına gəldi: asyncawait açar sözləri ilə asynchronous gəldi. İndi asinxron kodu demək olar ki, adi kimi sadə yazmaq olar.

Klassisik "asinxron ağrı" async/await olmadan

Müqayisə üçün baxaq, əgər interfeysi bloklamamaq üçün uzun əməliyyatı thread-lə edəcək olsaydıq, necə görünərdi:

// async/await olmadan nümunə, əl ilə
var thread = new Thread(() =>
{
    var data = DownloadFile("https://example.com/file");
    Console.WriteLine("Fayl yükləndi!");
});
thread.Start();

Bu üsul kifayət qədər kobuddur: thread-lərlə əl ilə məşğul olmaq, nəticəni "gözləmək" üçün sadə yolun olmaması və səhvlərin çətin həll olunması tələb olunur.

2. C#-də asinxronluq: sintaksis

Tərif: asyncawait nədir?

async — metodu "darıxdırıcı" olmamağa məcbur edən modifier-dir və onu asinxron edir. Belə metod adətən ya Task (və ya Task<T>), ya da ValueTask qaytarır. Bu, nəticənin bir az sonra gələcəyinə dair bir söz kimidir (onlayn mağazadan sifariş vermək kimi — sifariş verdin və gözləyirsən).

await — operatordur, deyir: "Bu sətirdə dayandır. Əməliyyat bitənə qədər gözlə, amma thread-i bloklama! Qalan işləri icra etməyə burax".

Asinxron metod necə görünür?

public async Task MyAsyncMethod()
{
    Console.WriteLine("Fayl yüklənir...");
    var data = await DownloadFileAsync("https://example.com/file"); // Nəticəni asinxron gözləyirik!
    Console.WriteLine("Hazır!");
}

DİQQƏT:

  • Metoda async modifier əlavə olunub.
  • Metod daxilində asinxron əməliyyat üçün await istifadə olunur.
  • Metod Task (və ya qaytarılan dəyər varsa Task<T>) qaytarır.

Vizualizasiya: async-metod çağırılarkən nə baş verir?

graph LR
A[MyAsyncMethod çağırışı] --> B[Await-dən əvvəl icra]
B --> C[DownloadFileAsync çağırışı]
C --> D{Gözləmə}
D --> |Fayl yüklənməyib| E[Thread-in azad edilməsi]
D --> |Fayl yüklənib| F[Await-dən sonra icra]
F --> G[Metodun tamamlanması]
  • İlk await-ə qədər metod sinkron şəkildə icra olunur.
  • await-də metod dayandırılır, idarə çağırana qaytarılır.
  • Asinxron əməliyyat bitdikdə, icra await-dən sonra davam edir — sanki heç nə olmamışdır.

3. Nümunə: async/await ilə asinxron yükləmə

Tədris tətbiqimiz internetdən mətn yükləsin və onun uzunluğunu çap etsin, digər kodu bloklamadan.

using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    // Asinxron metod (Task qaytarır)
    public static async Task DownloadAndPrintLengthAsync(string url)
    {
        Console.WriteLine("Yükləməyə başlayırıq...");

        // HttpClient istifadə edirik — o asinxron metodları dəstəkləyir
        using (var client = new HttpClient())
        {
            string data = await client.GetStringAsync(url);
            Console.WriteLine($"Yükləmə tamamlandı! Mətnin uzunluğu: {data.Length} simvol.");
        }

        Console.WriteLine("Metodun işi tamamlandı.");
    }

    static void Main()
    {
        // Asinxron əməliyyatı işə salırıq və onun bitməsini gözləyirik
        var task = DownloadAndPrintLengthAsync("https://www.example.com");
        task.Wait(); // Sadə konsol nümunələri üçün qəbul edilir. Real UI və ya web tətbiqlərdə bu çağırış bloklamaya və deadlock-a səbəb ola bilər.
    }
}

İzahat:

  • DownloadAndPrintLengthAsync — tamamilə asinxrondur, asyncawait sayəsində.
  • Metodun içində asinxron yükləmənin bitməsini await ilə gözləyirik.
  • Main()-də tapşırığı işə salıb açıq şəkildə onun bitməsini Wait() ilə gözləyirik. Müasir C#-də Main özünü də asinxron edə bilərsiniz (async Task Main) və sadəcə await yaza bilərsiniz.

4. Necə işləyir?

Sinkron və asinxron kod arasındakı fərq

SİNKRON VARİANT

Console.WriteLine("Başlanğıc");
string data = client.GetStringAsync(url).Result; // .Result thread-i bloklayır!
Console.WriteLine("Əməliyyat tamamlandı");

ASİNXRON VARİANT

Console.WriteLine("Başlanğıc");
string data = await client.GetStringAsync(url); // Thread bloklanmır
Console.WriteLine("Əməliyyat tamamlandı");

await "qapağın altında" necə işləyir?

await istifadə etdikdə, C# avtomatik olaraq metodunuzu iki (və ya daha çox) hissəyə "bölür": await-dən əvvəl olan hissə və await-dən sonrakı hissə. Çağırılan asinxron metod Task qaytardıqda, sizin metodunuz çağırana geri dönür, və Task tamamlandığı zaman icra await-dən sonra davam edir. Bütün bunlar avtomatik baş verir; thread-lər və switch-lərlə əl ilə məşğul olmağa ehtiyac yoxdur.

Maraqlı fakt: C# sizin asinxron metodunuzu state-machine-ə çevirir, hər bir await yeni "qaytarış nöqtəsidir".

Real tətbiqlərdə async/await istifadəsi

static async Task Main(string[] args)
{
    var downloadTask = DownloadAndPrintLengthAsync("https://www.example.com");
    // Yükləmə gedən vaxt başqa işlər görürük
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine($"İşləyirik... iterasiya {i}");
        await Task.Delay(500); // 0.5s pauza, işi simulasiya edirik
    }
    await downloadTask; // Yükləmənin bitməsini gözləyirik
}

İndi proqram həm nəsə yükləyir, həm də bloklanmır: "canlı" multitasking, demək olar ki, pişik kimi eyni anda yatır və qabı izləyir.

Asinxronluq ≠ multithreading

Gənclərin tez-tez səhv başa düşdüyü vacib fərq: asinxron kod eyni thread-də də işləyə bilər! Asinxronluq məqsədi thread-i bloklamamaqdır, yeni thread-lər yaratmaq deyil. OS thread-ləri bahalı resursdur! Asinxronluq uzun müddətli əməliyyatlardan (şəbəkə, fayl, timer və s.) gözləmək əvəzinə thread-i buraxmağa imkan verir.

Müqayisə cədvəli: nə zaman nə seçək?

Ssenari Thread/Task async/await
CPU-bound tapşırıqlar Bəli Bəli (Task.Run vasitəsilə)
I/O-bound tapşırıqlar Effektiv deyil İdealdır
Çoxlu paralellizm Çətin Asandır
Kodun sadəliyi Hardkor Oxumaq asandır

5. Faydalı nüanslar

Asinxron Main

Müasir C# versiyasında Main-i də asinxron etmək olar!

static async Task Main(string[] args)
{
    // Bütün asinxron kodu Main-də birbaşa await etmək olar
    await DownloadAndAnalyzeFileAsync("https://example.com/file");
}

Tipik səhv: await-i unuttunuz — task "axıb getdi"

SomeAsyncFunction(); // await etmirik, heç kim bitməsini gözləmir!

Nəticədə bu task "havada" işləyəcək — və əgər səhv olsa, siz bundan xəbərsiz ola bilərsiniz!

Nə vaxt async metod yazmamalısınız

  • Əgər metod daxilində bir ədəd belə asinxron əməliyyat (heç bir await) yoxdursa, onu async etməyin.
  • async void yazmaq məsləhət deyil (yalnız event handler olduqda icazə verilir).

Qısa qaydalar və tipik suallar

  • await-i async-metoddan kənarda istifadə etmək olarmı? Xeyr! Həmişə async kimi işarələnmiş metodlar daxilində istifadə edilir.
  • Bir metoddə bir neçə await ola bilərmi? Bəli, istənilən sayda ola bilər — hər biri bir "gözləmə nöqtəsidir".
  • Nəticə qaytarmaq istəyirəm — nə etdim? Task<T> istifadə edin və normal return yazın.
  • Bir neçə asinxron task-ı necə kombinə etmək olar? Əlbəttə! Bir neçə task-ı paralel işə salıb hamısını Task.WhenAll ilə gözləmək olar.

6. async/await istifadə zamanı tipik səhvlər

Səhv №1: "alov topu" — asinxron task çağırıldıqdan sonra await etməmək.

DownloadAndPrintLengthAsync("https://www.example.com");
Console.WriteLine("Hər şey icra olundu!"); // Əslində yükləmə hələ gedir!

Kod asinxron əməliyyatın tamamlanmasını gözləməyəcək. Bütün asinxron task-lar ya await edilməli, ya da açıq şəkildə Wait() ilə idarə olunmalıdır (amma ikinci yol təhlükəlidir və bloklamalara gətirib çıxara bilər).

Səhv №2: sinkron və asinxron kodu .Result və ya .Wait() ilə qarışdırmaq.

Bu anti-pattern-dir və asinxronluğun bütün üstünlüklərini sıfırlayır. UI və ASP.NET tətbiqlərində bu demək olar ki, həmişə deadlock-a gətirib çıxarır: asinxron task thread-in azad edilməsini gözləyir, amma thread özü bu task-ın bitməsini gözləmək üçün bloklanıb. Mantranı yadda saxlayın: "async all the way" (asinxronluq ən yuxarıya qədər).

Səhv №3: async void istifadəsi.

async void metodları gözləmək mümkün deyil (await edilə bilməz), və onlardan atılan istisnalar normal try-catch ilə tutulmur və adətən tətbiqin qəza ilə bitməsinə səbəb olur. Yeganə qəbul edilən istifadəsi event handler-lərdir (məsələn, async void Button_Click(...)), hansı ki, tələb olunan signature-ya görə belə olmalıdır. Digər hallarda async Task istifadə edin.

Səhv №4: metodda await olmadan lazımsız async.

Əgər metodu async kimi işarələyirsiniz, amma içində heç bir await yoxdursa, kompilyator xəbərdarlıq verəcək. Belə kod tam olaraq sinkron şəkildə icra olunur, amma əlavə "state machine" yaratmaq kimi overhead yaradır. Bu yanıltıcıdır və performansı aşağı sala bilər.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION