Cancellation Token

Merhaba,

Bu yazımızda, programlamada, yapılmakta olan işlemlerin (özellikle asenkron işlemlerin) iptal edilmesi durumunda kullandığımız oldukça basit bir yapı olan Cancellation Token konusunu inceleyeceğiz.

Cancellation Token, uzun sürebilen asenkron işlemleri iptal etmek için kullanılan, System.Threading namespace‘i altında bulunan bir struct türüdür. “İptal Tokenı” anlamına gelmekte olup yapılmakta olan, sistemi yorucu veya veri trafiğini arttırıcı bir işlemin iptal edilip edilmediğini belirli aralıklarla kontrol ederek, eğer iptal edilmişse işlemi durdurma ilkesine dayanır. Bu sayede işlemin boşuna devam etmesine izin verilmez ve sistem kaynakları israf edilmemiş olur.

Oldukça basit bir mantığa dayanan bu yapının yaptığı işi isterseniz kendi oluşturacağınız bir türle de tasarlayabilirsiniz. Ancak .NET’te tercih edilen kullanım bu şekildedir.

Bir .NET Console uygulamasında aşağıdaki gibi bir kod bloğu düşünün.

using System;
using System.Threading;

async void IslemAsync(CancellationToken token)
{
    for (int i = 1; i <= 10; i++)
    {
        // İşlemin iptal edilip edilmediği her adımda kontrol edilir.
        token.ThrowIfCancellationRequested();

        Console.WriteLine($"Adım {i}");
        await Task.Delay(1000); // Bir saniye bekle
    }
}

// CancellationToken'ı oluşturan kaynak nesne.
var tokenSource = new CancellationTokenSource();

// Asenkron işlemin başlatılması ve token'ın gönderilmesi.
IslemAsync(tokenSource.Token);

Thread.Sleep(3000);     // Asenkron işlem devam ededursun, üç saniye bekle
tokenSource.Cancel();   // İptal isteği gönder (IsCancellationRequested'i true yap)

Görüleceği üzere IslemAsync() devam ederken, her bir döngüde token için bir iptal talebi alınıp alınmadığı kontrol ediliyor. Böylece kullanıcının bir iptal butonuna tıklaması veya tarayıcıyı kapatması gibi bir durumda Cancellation Token altında bulunan IsCancellationRequested değeri true olacağından işlem durduruluyor.

İstersek ThrowIfCancellationRequested() metodunu çağırmak yerine if ve try-catch blokları kullanarak ilgili exception‘ı kendimiz de fırlatabiliriz. Bu örneği de senkron bir metod kullanarak vereceğim. Bu durumda kodlarımız aşağıdaki gibi olur.

using System;
using System.Threading;

void Islem(CancellationToken token)
{
    for (int i = 1; i <= 10; i++)
    {
        // İşlemin iptal edilip edilmediği bir if bloğuyla kontrol ediliyor.
        if (token.IsCancellationRequested)
        {
            Console.WriteLine("İptal isteği geldi. İşlem durduruluyor.");
            throw new OperationCanceledException();
        }

        Console.WriteLine($"Adım {i}");
        Thread.Sleep(1000); // Bir saniye bekle
    }
}

// CancellationToken'ı oluşturan kaynak nesne.
var tokenSource = new CancellationTokenSource();

// İşlemin asenkron olarak başlatılması.
var task = Task.Run(() => Islem(tokenSource.Token), tokenSource.Token);

// Kullanıcının bir müddet sonra iptal etmek istediğini varsayalım.
Console.WriteLine("İptal etmek için Enter'a basın.");

// Enter'a basınca aşağıdaki Cancel() metodu çalışır ve iptal isteği gönderilir.
Console.ReadLine();

// Bu işlem IsCancellationRequested değerini true olarak ayarlar.
tokenSource.Cancel();

try
{
    await task;
}
catch (OperationCanceledException)
{
    Console.WriteLine("İşlem iptal edildi.");
}

Fark ettiyseniz burada, senkron bir metodu Task sınıfının yardımıyla asenkron olarak tetikledik. Uygun senaryoyu elbette kendiniz belirleyeceksiniz.

Umarım yararlı olmuştur. Bir sonraki yazımızda görüşmek üzere…

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir