CodeGym /Kurslar /C# SELF /Əməliyyatların ləğvi: Canc...

Əməliyyatların ləğvi: CancellationToken

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

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
Task.Delay
✔
await Task.Delay(1000, token);
HttpClient.GetAsync
✔
await client.GetAsync(url, token);
Stream.ReadAsync
✔
await stream.ReadAsync(buffer, 0, len, token);
Task.Run
✔
Task.Run(() => ..., token);
File.ReadAllTextAsync
✔
await File.ReadAllTextAsync(path, token);
Thread.Sleep
✖ 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!)
MyLongMethod(token)

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.

2
Tapşırıq
C# SELF, səviyyə, dərs
Bağlanıb
Ləğv etmə dəstəyi ilə sadə ədədlərin axtarışı
Ləğv etmə dəstəyi ilə sadə ədədlərin axtarışı
1
Sorğu/viktorina
, səviyyə, dərs
Əlçatan deyil
Task və Thread müqayisəsi
Paralel məlumat emalı
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION