1. Giriş
Siz asinxron (və ya uzunmüddətli) əməliyyatı başladanda, istifadəçi (və ya başqa kod) birdən deyə bilər: "Dayan! Artıq lazım deyil! Dayan!". Məsələn, istifadəçi nəhəng faylın yüklənməsini ləğv edə, proqram pəncərəsini bağlaya və ya böyük verilənlər bazasında axtarışı ləğv edə bilər. Ləğv dəstəyi olmasa, programınız boşuna işləməyə və resursları yeyməyə davam edə bilər — istifadəçi və kompüter üçün yaxşı deyil.
Ləğv üçün tipik ssenarilər:
- Fayl yükləməsinin ləğvi və ya məlumatların göndərilməsinin ləğvi.
- İstifadəçinin tələbiylə mürəkkəb məlumat emalından tez çıxmaq.
- Uzunmüddətli işin qəfil dayandırılması/pausası, artıq aktuallığını itirmişsə.
Ləğv — istifadəçi dostu, reaktiv və resurslara qənaət edən tətbiqlər üçün sizin gizli inqrediyentinizdir.
.NET-də asinxron əməliyyatları necə ləğv etmək olar?
.NET-də uzunmüddətli tapşırıqları ləğv etmək üçün "ləğv tokeni" (CancellationToken) konsepti istifadə olunur. Bu xüsusi obyekt tapşırığın bütün komponentlərinə ötürülür. Kimsə əməliyyatı ləğv etməyi xahiş edərsə — token dərhal bu haqda proqramın bütün maraqlı hissələrinə xəbər verir. Praktikada bu qırmızı bayraq kimidir: kim birinci görsə — dayanacaq.
.NET-də bu mexanizm iki əsas siniflə reallaşdırılıb:
- CancellationTokenSource — ləğv tokenini yaradır və onu idarə edir.
- CancellationToken — asinxron metodlara ötürülür ki, onları ləğv etmək mümkün olsun.
Vacib: öz-özünə ləğv tokeni kodun icrasını kəsmir, o yalnız "siqnal" verir — tətbiqiniz isə bu siqnala necə və nə zaman reaksiya verəcəyinə özü qərar verir.
2. Ləğv tokeni yaradırıq və tapşırığı ləğv edirik
Gəlin sadə nümunə ilə göstərək (tədris konsol tətbiqimizi inkişaf etdirəcəyik).
Nümunə: ləğvlə sadə asinxron əməliyyat
using System;
using System.Threading;
using System.Threading.Tasks;
namespace DemoApp
{
class Program
{
static async Task Main()
{
// CancellationTokenSource yaradırıq
CancellationTokenSource cts = new CancellationTokenSource();
// Asinxron tapşırığı işə salırıq
Task longRunningTask = DoWorkAsync(cts.Token);
Console.WriteLine("Əməliyyatı ləğv etmək üçün hər hansı düyməni basın...");
Console.ReadKey();
// Ləğv tələb edirik
cts.Cancel();
try
{
await longRunningTask;
}
catch (OperationCanceledException)
{
Console.WriteLine("Əməliyyat ləğv edildi!");
}
}
// Ləğvi dəstəkləyən asinxron metod
static async Task DoWorkAsync(CancellationToken cancellationToken)
{
for (int i = 0; i < 10; i++)
{
// Ləğv siqnalını yoxlayırıq
cancellationToken.ThrowIfCancellationRequested();
Console.WriteLine($"Addımın icrası {i + 1}/10...");
await Task.Delay(1000); // 1 saniyə gecikmə
}
Console.WriteLine("Əməliyyat uğurla başa çatdı!");
}
}
}
Bu necə işləyir?
- Biz CancellationTokenSource (cts) yaradırıq və ondan token (cts.Token) alırıq.
- Bu tokeni asinxron əməliyyatımıza ötürürük.
- DoWorkAsync() daxilində müntəzəm olaraq tokeni ThrowIfCancellationRequested() ilə yoxlayırıq. Əgər istifadəçi tapşırığın ləğvini tələb edərsə — metod OperationCanceledException atacaq və tapşırıq dayandırılacaq.
- Main() daxilində hər hansı düymənin basılmasını gözləyir və cts.Cancel() çağırırıq ki, dayandırmaq tələbini "siqnal edək".
Əgər siz cancellationToken.IsCancellationRequested yoxlamazsanız və ya ThrowIfCancellationRequested() çağırmazsanız, tapşırığınız olduğu kimi işləməyə davam edəcək — token yalnız informasiya bayrağıdır.
3. CancellationToken: necə qurulub? Bir az sehr
Ləğv tokeni — metodlar və tapşırıqlar arasında rahatlıqla ötürülə bilən obyektdir. Bu bir neçə üstünlük verir:
- Eyni token bir neçə asinxron və sinxron əməliyyatda istifadə oluna bilər.
- Bir CancellationTokenSource-dan gələn token istifadə olunursa, "qrup ləğvi" təşkil etmək olar — bütün tapşırıqlar bir anda ləğv edilir.
- Ləğv tokeni həddindən artıq müdaxiləçi deyil: onu görməzdən gətsəniz, kod əvvəlki kimi işləyir.
Ləğvi idarə etmək: tokeni harada və necə yoxlamalı?
Ləğv bayrağının qaldırılıb-qaldırılmadığını yoxlamaq məntiqə uyğun olan yerlərdə lazımdır: dövrədə, uzun emalın hər addımında, mərhələlər arasında və s.
// Hər hansı bir yoxlama anında
if (cancellationToken.IsCancellationRequested)
{
Console.WriteLine("Əməliyyat ləğv edildi! Çıxırıq...");
return;
}
// Və ya belə (qısa və istisna ilə)
cancellationToken.ThrowIfCancellationRequested();
Adətən ThrowIfCancellationRequested() istifadə olunur — o xüsusi istisna atır və onu çağıran kodda tutmaq olar.
4. Standart kitabxananın asinxron metodları
Çoxlu .NET sinifləri və metodları (xüsusilə asinxron olanlar) CancellationToken-i "qutudan çıxanda" dəstəkləyir. Bunlardan istifadə edərək əməliyyatları düzgün dayandırmaq mümkündür və tövsiyə olunur.
Faylı asinxron oxuma nümunəsi:
using System.IO;
using System.Threading;
using System.Threading.Tasks;
class FileDemo
{
public static async Task ReadFileWithCancelAsync(string filePath, CancellationToken cancellationToken)
{
using FileStream stream = File.OpenRead(filePath);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
{
// Məlumatı emal edirik...
// Əgər ləğv tokeni tələb edilibsə, ReadAsync özü OperationCanceledException atacaq
}
}
}
FileStream.ReadAsync və CancellationToken haqqında daha ətraflı rəsmi sənədlərdə oxuyun.
5. Faydalı nüanslar
Timeout — o da ləğvdir!
Siz əməliyyatları müəyyən vaxt keçdikdən sonra avtomatik olaraq ləğv edə bilərsiniz. Bunun üçün CancellationTokenSource-u "vaxtla" yaratmaq olar:
// Məsələn, 5 saniyəlik timeout ilə CancellationTokenSource yaratmaq
CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
Beş (5) saniyədən sonra token avtomatik olaraq "qaldırılacaq" və onunla işləyən əməliyyatlar növbəti yoxlamada dayandırılacaq. Bu əbədi gözləmək istəmədiyiniz hallarda çox rahatdır.
Ləğv zamanı nə baş verir?
Siz CancellationTokenSource üzərində Cancel() çağırdıqda, həmin tokeni istifadə edən və onun vəziyyətini yoxlayan bütün metodlar bu dəyişikliyi görəcəklər. Amma əgər sizin kod tokeni yoxlamırsa — ləğv baş verməyəcək.
Tipik səhv: tokeni bütün asinxron və uzun əməliyyatlara ötürməyi unutmaq. Bu halda əməliyyatın bir hissəsi ləğv edilə, bir hissəsi isə işləməyə davam edə bilər.
Vizualizasiya: ləğv necə keçir
sequenceDiagram
participant Main as Baş thread
participant CTS as CancellationTokenSource
participant Task as Asinxron tapşırıq
Main->>CTS: CTS yaradır, token alır
Main->>Task: tokeni asinxron tapşırığa ötürür
Note over Task: Tapşırıq dövri olaraq tokeni yoxlayır
Main->>CTS: Cancel() çağırır
CTS-->>Task: token "ləğv edildi" statusu alır
Task-->>Main: OperationCanceledException atır
Main->>Main: istisnanı tutur və işi bitirir
Ləğv harada tətbiq olunur?
- Asinxron yükləmələr və server sorğuları: pis internet və ya yorulan istifadəçi zamanı ləğv etmək olar.
- Böyük hesablamalar: timeout və ya istifadəçi tələbi ilə dayandırmaq olar.
- Şəbəkə əməliyyatları, fayllarla iş, fon rejimində böyük kolleksiyaların emalı.
Beləliklə, asinxron əməliyyatların ləğvi ilə tanışlıq bitdi — indi tətbiqiniz təkcə sürətli deyil, həm də daha diqqətli olacaq!
6. Tövsiyələr və tipik səhvlər
Unutmayın cancellation tokeni bütün dəstəkləyən metodlara və çağırışlara ötürmək. Əgər haradasa tokeni ötürməsəniz — əməliyyat "yapışa" və dayanmaya bilər.
Tokeni müntəzəm yoxlayın — xüsusən uzun dövrlərdə, fayl emalında və ya böyük həcmdə yükləmələrdə. IsCancellationRequested və ya ThrowIfCancellationRequested() istifadə edin.
Sən demə "bəsitcə" söndürməyə çalışmayın: xaricdən thread-i və ya task-ı zorla bitirməyə çalışmaq olmaz — ləğv tokeni xahişdir, zorakılıq deyil.
Standart kitabxananın ReadAsync, Delay, HttpClient.SendAsync və s. kimi funksiyaları artıq token vasitəsilə ləğvi dəstəkləyir. Onlardan istifadə edin!
Ləğvi emal edərkən məhz OperationCanceledException-ı tutun — bu ləğvin düzgün və istək əsasında baş verdiyini bildirən xüsusi istisnadır.
GO TO FULL VERSION