1. Giriş
Təsəvvür edin ki, kodunuz mağazada növbədir. Əgər sinxron metodu işə salırsınızsa, bütün xətt (sizin növbəniz) kassirin bir müştəri ilə işini bitirməsini gözləyir, sonra növbətiyə keçilir. Amma metod asinxrondursa, siz sadəcə alış-verişi kassaya qoyub öz işinizlə məşğul ola bilərsiniz, kassir işini bitirəndə isə sizi çağıracaq.
Asinxron metod (async-metod) .NET-də xüsusi bir “etiket”lə (async) işarələnmiş adi metoddur, bu da içəridə await operatorundan istifadə etməyə imkan verir — digər asinxron əməliyyatları (məsələn, şəbəkə və ya fayl əməliyyatları) bloklamadan gözləmək üçün, əsas thread-i bloklamadan. Elə bu “etiket” sıradan sinxron mağazanı növbəsiz müasir xidmətə çevirir.
Asinxron metodun əsas imzası
Asinxron metod mütləq imzada async modifikatoru ilə elan edilir. Ən sadə nümunə belədir:
public async Task MyAsyncMethod()
{
// Sizin asinxron kodunuz burda
}
Asinxron metodların qaytardığı tiplər:
| Qaytarılan tip | Təsvir | Nümunə |
|---|---|---|
|
Metod asinxron şəkildə işləyir, lakin nəticə qaytarmır | |
|
Metod asinxron işləyir və T tipində nəticə qaytarır | |
|
Yalnız event-lər üçün istifadə olunur. Başqa yerlərdə tövsiyə olunmur! | |
|
Yüksək performanslı ssenarilər üçün, nəticə tez-tez sinxron olaraq hazır olduqda | — |
Vacib: async void-dan yalnız event handler-lərdə istifadə edin! Əks halda səhvlərin düzgün işlənməsi itə bilər.
2. Asan asinxron metod nümunəsi
Gəlin təlim proqramımıza qayıdaq (məsələn, adi konsol proqramı) və şəbəkədən məlumat alan asinxron metod əlavə edək. Biz gecikməni emulyasiya edəcəyik.
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Asinxron metod işə düşür...");
await MyFakeDownloadAsync();
Console.WriteLine("Asinxron əməliyyat tamamlandı!");
}
static async Task MyFakeDownloadAsync()
{
Console.WriteLine("Yükləməyə başlayırıq (2 s gecikmə emulyasiya edilir)...");
await Task.Delay(2000); // Uzun əməliyyatı emulyasiya edirik
Console.WriteLine("Yükləmə tamamlandı!");
}
}
Nümunəyə şərhlər:
- async sözü Main və MyFakeDownloadAsync-də göstərilib.
- await operatoru yalnız async ilə işarələnmiş metodların içində istifadə oluna bilər.
- Task.Delay(2000) uzun əməliyyatı (məsələn, şəbəkə sorğusunu) emulyasiya edir.
- await göründükdə thread bloklanmır — Main əməliyyatın bitməsini gözləmək üçün "dayandırılır".
3. Asinxron metodun içində nə baş verir?
Kompilyator async sözünü gördükdə metodu "state machine"ə çevirir, hansı ki dayandığı yeri, lokal dəyişənləri yadda saxlayır və awaited əməliyyat bitəndən sonra icrayı davam etdirir.
Çox sadələşdirilmiş sxem belədir:
+-----------------------------------------------------------+
| Asinxron metodun çağırışı (məsələn, await X) |
+-------------------------+---------------------------------+
|
v
Əməliyyat bitibmi? (Task.Completed deyil?)
| |
| bəli | xeyr
v v
İcranı dayandır Dərhal qaytar
yadda saxla nəticəni
kontekst (və ya exception at)
|
Asinxron əməliyyat tamamlanır...
|
v
State machine metodu "oyadır",
icra await-dan sonrakı nöqtədən davam edir
Detallarını əzbərləməyə ehtiyac yoxdur: kontekst (dayanma yeri və lokal dəyişənlər) saxlanılır və əməliyyat bitəndə avtomatik bərpa olunur.
async və await sözlərini harada istifadə etmək olar (və olmaz)
- async metodun (və ya lambda-nın) deklarasiyasından əvvəl qoyulur.
- async metodun içində await istifadə etmək olar (və tövsiyə olunur).
- await-i async olmayan metodda yazmağa çalışsanız — kompilasiya xətası alacaqsınız.
- async göstərib amma metodda heç bir await yoxdursa — xəbərdarlıq alınacaq; metod sinxron icra olunacaq və artıq tamamlanmış Task qaytaracaq.
4. Qaytarılan dəyərlərin variantları və xüsusiyyətləri
Task nəticəsi
Metod asinxron əməliyyatlar həyata keçirir, amma dəyər qaytarmırsa, Task istifadə edin:
public async Task SaveToFileAsync(string path)
{
await Task.Delay(1000);
// Fayla nəsə yazırıq
}
Task<T> nəticəsi
Nəticə lazımdırsa, Task<T> istifadə edin:
public async Task<int> CalculateAsync()
{
await Task.Delay(500);
return 42;
}
Çağırış:
int result = await CalculateAsync();
async void nəticəsi
Yalnız eventlər üçün istifadə edin! Məsələn, düymənin click handler-i:
private async void Button_Click(object sender, EventArgs e)
{
await Task.Delay(1000);
// Başqa işlər görürük
}
Niyə adi metodlarda async void istifadə etmək olmaz? Çünki belə metodun nə vaxt qurtardığını bilməzsiniz və içindəki istisnaları düzgün tutmaq mümkün olmur.
ValueTask və ValueTask<T> nəticələri
Yüksək performanslı kitabxanalar üçün daxil edildi, nəticə tez-tez sinxron hazır olduqda əlavə Task ayırmalarını azaltmağa kömək edir. Karyeranın başlanğıcında bunu istifadə etməyə ehtiyac yoxdur — nadir hallarda rast gələcəksiniz.
5. Nümunə: nəticə qaytaran asinxron kalkulyator
Proqram iki ədədin cəmini "gecikmə ilə" hesablasın, sanki çox ağır əməliyyatdır:
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Birinci ədədi daxil edin:");
int a = int.Parse(Console.ReadLine()!);
Console.WriteLine("İkinci ədədi daxil edin:");
int b = int.Parse(Console.ReadLine()!);
Console.WriteLine("Hesablayırıq...");
int sum = await CalculateSumAsync(a, b);
Console.WriteLine($"Cəmi: {sum}");
}
static async Task<int> CalculateSumAsync(int x, int y)
{
await Task.Delay(2000); // "Uzun" əməliyyat
return x + y;
}
}
Burada vacib olan:
- CalculateSumAsync — asinxron metoddur, Task<int> qaytarır və içərisində await var.
- Main-də çağırış await ilə edilir (xatırlatma: C# 7.1-dən başlayaraq Main asinxron ola bilər).
- Cəm hesablanarkən thread bloklanmır — progress göstərmək və ya başqa iş görmək olar.
6. Daxili çağırışlar və daxilində await
Asinxron metod başqa asinxron metodu çağıra bilər, o da başqa birini. Bütün zəncir avtomatik davam edir:
public async Task<int> StartWorkAsync()
{
int data = await GetDataAsync();
int result = await ProcessDataAsync(data);
return result;
}
Hər şey sadədir: bir əməliyyatın bitməsini gözləyirik, sonra digərinə keçirik.
7. Tələlər və tez-tez edilən səhvlər
1. async-i unutmayın!
Əgər async-i unutmusunuzsa, kompilyator metodun içində await gördükdə şikayət edəcək və kodu yığmayacaq.
2. Adi metodlarda async void-dan istifadə etməyin
Asinxron void-metodlar (event handler-lər istisna olmaqla) istisnalar üçün "qara dəlik"dir. Onlardakı səhvlər batıb gedə bilər və siz bundan xəbərsiz ola bilərsiniz.
3. Asinxron metod await olmadan
Belə etmək olar, amma mənasızdır — metod sinxron icra olunacaq və artıq tamamlanmış Task qaytaracaq.
public async Task DoNothingAsync()
{
// Hop, heç bir await yoxdur!
}
4. Sinxron olmayan metoddan Task qaytarmaq
Bu, interfeysləri vahidləşdirmək üçün edilir: bəzi əməliyyatlar həqiqətən asinxrondur, bəziləri isə dərhal hazır olur.
public Task<int> Foo()
{
// return 42; // Belə olmaz!
return Task.FromResult(42); // Olur, amma burada heç bir asinxronluq yoxdur.
}
GO TO FULL VERSION