1. CancellationToken ilə tanışlıq
Təsəvvür edin: uzun müddətli fayl yükləməsi başladırsınız, sonra yadınıza düşür ki, İnternet tarif üzrədir və gigabaytlar bahalıdır. Və ya istifadəçi səhvən hesablamanı başladıb, sonra fikrini dəyişib. O, «Ləğv et» düyməsini basmaq və bitməsini gözləməmək istəyir. Müasir tətbiqlər reaktiv olmalıdır, buna görə hər an dayandırma siqnalını ötürməyi və asinxron əməliyyatı düzgün formada kəsməyi bacarmalıyıq.
Bunun üçün .NET-də xüsusi ləğv infrastrukturu mövcuddur — CancellationToken.
CancellationToken (sözün əsl mənasında "ləğv tokeni") — uzun əməliyyatın içərisinə ötürdüyünüz xüsusi obyektdir. Hər an ləğvı CancellationTokenSource vasitəsilə siqnal verə bilərsiniz, əməliyyat isə periodik olaraq tokeni (məsələn, IsCancellationRequested) yoxlamalı və lazım gəldikdə ThrowIfCancellationRequested()-u çağıraraq düzgün şəkildə bitməlidir.
Qısaca necə işləyir?
- Bir obyekt var — CancellationTokenSource, o tokenlər yaradıb onları ləğv etməyi bacarır (metod Cancel()).
- CancellationToken özü — "siqnal bayrağı"dır, bir neçə əməliyyata paylamaq olar (source-un Token xüsusiyyəti vasitəsilə).
- Əməliyyat periodik olaraq tokeni yoxlayır: əgər ləğv tələb edilibsə, işi dayandırır (ya da OperationCanceledException atır).
Analqoriya: siz rəhbərsiniz (siz — CancellationTokenSource). İşçilərə "beyc"lər paylayırsınız (bunlar CancellationToken). Siz hər şeyi ləğv etməyə qərar verəndə qırmızı bayraq qaldırırsınız — və bütün beyci olanlar dərhal geri çəkilir, yarımçıq qalmış naharı qoyub gedirlər.
2. CancellationToken-dən necə istifadə etmək
CancellationTokenSource yaratmaq
var cts = new CancellationTokenSource();
Öz tokeni əldə etmək
CancellationToken token = cts.Token;
Tokeni asinxron metoda ötürmək
.NET-in bir çox standart asinxron metodları CancellationToken tipində parametr qəbul edir. Məsələn, HttpClient.GetAsync, Stream.ReadAsync, Task.Delay və s.
Nümunə — ləğvlə gecikmə:
await Task.Delay(10000, token); // 10 saniyə gözləyir — amma ləğv edilə bilər!
Ləğv tələb etmək (məsələn, düymə və ya taymer ilə)
cts.Cancel(); // Bu tokeni alan bütün əməliyyatlar ləğv barədə xəbərdar olacaqlar
Metod daxilində tokeni yoxlamaq
Xüsusən uzun və dövrü iş görən metodlarda ləğv bayrağını müntəzəm yoxlamaq və OperationCanceledException-u atmaq lazımdır, əgər ləğv tələb edilibsə:
token.ThrowIfCancellationRequested();
Yaxud sadəcə xüsusiyyəti yoxlamaq:
if (token.IsCancellationRequested)
{
// Resursları azad edirik, metoddan çıxırıq
}
3. Nümunə: tədris tətbiqimizə ləğv əlavə edək
Tutaq ki, saytından məlumat yükləyən tətbiqimiz var. Gəlin istifadəçi fikrini dəyişsə yükləməni ləğv etmək imkanı əlavə edək.
Asinxron yükləmə üçün əsas nümunə
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
class Downloader
{
public async Task DownloadAsync(string url)
{
var client = new HttpClient();
string content = await client.GetStringAsync(url); // Ləğv olmadan
Console.WriteLine("Yükləmə tamamlandı!");
}
}
CancellationToken əlavə edək
public async Task DownloadAsync(string url, CancellationToken token)
{
var client = new HttpClient();
string content = await client.GetStringAsync(url, token); // İndi ləğv dəstəyi ilə!
Console.WriteLine("Yükləmə tamamlandı!");
}
Çağıran tərəfdən ləğvi idarə etmək
static async Task Main(string[] args)
{
var downloader = new Downloader();
var cts = new CancellationTokenSource();
Console.WriteLine("Yükləmək üçün URL daxil edin:");
string url = Console.ReadLine();
var downloadTask = downloader.DownloadAsync(url, cts.Token);
Console.WriteLine("Yükləməni ləğv etmək üçün hər hansı bir düyməni basın...");
Console.ReadKey();
cts.Cancel(); // Ləğv siqnalı
try
{
await downloadTask;
}
catch (OperationCanceledException)
{
Console.WriteLine("Yükləmə istifadəçi tərəfindən ləğv edildi!");
}
}
Elə sadə! İstifadəçi əməliyyatı istənilən vaxt kəsə bilər.
4. CancellationTokenSource və metodların qarşılıqlı əlaqəsi
flowchart TD
A["İstifadəçi kodu (Main)"] -- yaradır --> B["CancellationTokenSource"]
B -- verir --> C["CancellationToken"]
C -- ötürülür --> D["Asinxron əməliyyat"]
A -- çağırır Cancel() --> B
D -- periodik yoxlayır --> C
C -- ləğv haqqında bildirir --> D
D -- Exception atır və ya işi bitirir --> A
5. Ləğvin emalı
Əməliyyat tokeni aldıqda iki davranış variantı var:
.NET metodları özləri exception atacaq.
Əgər siz standart metodları, məsələn Stream.ReadAsync, HttpClient.GetAsync və ya Task.Delay çağırırsınızsa və onlara token ötürürsünüzsə, Cancel() çağırıldıqda bu metodlar özləri OperationCanceledException-u atacaqlar. Sizə yalnız bunu tutmaq qalır.
İstifadəçi tərəfindən yazılmış asinxron kod.
Əgər özünüz "uzun" əməliyyatlar yazırsınızsa (məsələn, dövri emal və ya kompleks hesablamalar), sizin məsuliyyətiniz — token.IsCancellationRequested-i müntəzəm yoxlamaq (və ya token.ThrowIfCancellationRequested()-u çağırmaq), beləliklə ləğvə düzgün reaksiya vermək.
Nümunə: ləğvin əl ilə yoxlandığı "uzun" əməliyyat
public async Task CalculatePrimesAsync(int max, CancellationToken token)
{
for (int i = 2; i < max; i++)
{
token.ThrowIfCancellationRequested(); // Ləğvi yoxlayırıq
if (IsPrime(i))
{
Console.WriteLine($"Mersəl ədədi: {i}");
await Task.Delay(100, token); // "İstirahət" veririk (ləğv edilə bilər)
}
}
Console.WriteLine("Hesablama tamamlandı!");
}
private bool IsPrime(int n)
{
for (int i = 2; i <= Math.Sqrt(n); i++)
if (n % i == 0) return false;
return true;
}
6. Faydalı nüanslar
CancellationToken-i dəstəkləyən metodlar və siniflər
| Sinif/metod | CancellationToken-i dəstəkləyirmi? | İstifadə nümunəsi |
|---|---|---|
|
✔ | |
|
✔ | |
|
✔ | |
|
✔ | |
|
✔ | |
|
✖ | Dəstəkləmir; daha yaxşısı Task.Delay-dən istifadə etməkdir |
| Sizin metodlarınız | ✔ (əgər dəstək əlavə etsəniz!) | |
Ləğv edilə bilən əməliyyatın həyat dövrü
sequenceDiagram
participant Istifadechi
participant Main
participant CancellationTokenSource
participant AsinxronEmeliyyat
Istifadechi->>Main: Əməliyyatı işə salır
Main->>CancellationTokenSource: CTS yaradır
Main->>AsinxronEmeliyyat: İşə salır və CancellationToken ötürür
Istifadechi->>Main: "Ləğv" düyməsini basır
Main->>CancellationTokenSource: Cancel() çağırır
AsinxronEmeliyyat->>AsinxronEmeliyyat: Ləğvi görür (\nIsCancellationRequested)
AsinxronEmeliyyat-->>Main: OperationCanceledException atır
Main->>Istifadechi: "Əməliyyat ləğv edildi" mesajını göstərir
Real həyatda harada istifadə olunur
- UI-tətbiqləri: İstifadəçi pəncərəni bağlamaq və ya əməliyyatı ləğv etmək istədikdə uzun yükləmələri, hesablamaları, fayl əməliyyatlarını dayandırmaq.
- Server tətbiqləri: Əgər client bağlantısını kəsibsə — sorğunun emalını dərhal ləğv etmək resurslara qənaət edir.
- Böyük məlumatların emalı: Tapşırıqlar çox uzun ola bilər — hesablamaları və ya migrasiyaları dayandırmaq üçün həmişə imkan olmalıdır.
- Avadanlıqla inteqrasiya: Skan etmə, çap və digər əməliyyatlar bəzən dərhal dayandırılmalıdır — ləğv dəstəyi burada vacibdir.
7. CancellationToken ilə işləyərkən tipik səhvlər
Səhv №1: Tokenin yoxlanmasını görməməzlikdən gəlmək.
Əgər əməliyyat token.IsCancellationRequested-i yoxlamır və ya ThrowIfCancellationRequested()-u çağırmırsa, ləğv zamanı dayanmır və resursları boş yerə sərf edir.
Səhv №2: OperationCanceledException-in düzgün emal edilməməsi.
Əgər OperationCanceledException-i tutmasanız, tətbiq gözlənilmədən dayana bilər. Həmişə ləğvi emal etmək üçün try-catch-dən istifadə edin.
Səhv №3: Ləğv zamanı resursların düzgün idarə olunmaması.
Ləğv əməliyyatı dəyişiklikləri avtomatik geri qaytarmır (məsələn, fayllarda və ya verilənlər bazasında). Resursları əl ilə təmizləmək lazımdır, bunu catch blokunda edin.
Səhv №4: Artıq ləğv edilmiş tokenin ötürülməsi.
Əgər token artıq ləğv edilibsə, metod dərhal exception atacaq, bu da əgər nəzərə alınmayıbsa iş məntiqini poza bilər.
GO TO FULL VERSION