CodeGym /Kurslar /C# SELF /Asinxron əməliyyatlarda səhətlərin emalı (

Asinxron əməliyyatlarda səhətlərin emalı ( async/ await)

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

1. Giriş

Əvvəlcə vacib sual: niyə asinxron metodlara sadəcə etibar edib hər şeyin həmişə düzgün işləyəcəyini gözləmək olmaz? Fayl əməliyyatları tez-tez istisna atır — faylı silmiş ola bilərlər, yaddaş bitmiş ola bilər, icazə çatmaya bilər və ya fayl bloklanmış ola bilər. Sinxron kodda bu problemləri adi try-catch blokunda tutardınız. Asinxron kodda da fəlsəfə eynidir, amma incə məqamlar var: xəta metodun çağırıldığı anda deyil, əməliyyatın əslində yerinə yetirildiyi vaxt baş verə bilər.

Xəta yaranma anı

Sinxron kodda StreamReader.Read() ilə oxuyarkən istisna dəqiq çağırış sətrində atılacaq — catch-də tutdunuz və yaxşıdır.
Asinxron kodda (await stream.ReadAsync()) xəta əməliyyat başladığı anda deyil, tapşırığın (Task) tamamlandığı və uğursuzluqla nəticələndiyi await zamanı düşəcək. Əgər await-ı unutmusunuzsa, xəta müəyyən müddət «görünməz» qala bilər.

2. Asinxron metodlarda istisnaları necə tutmaq

Gəlin dərhal tipik şablona baxaq:


try
{
    using FileStream fs = new FileStream("myfile.txt", FileMode.Open);
    byte[] buffer = new byte[1024];
    int bytesRead = await fs.ReadAsync(buffer, 0, buffer.Length);
    // Daha sonra emal...
}
catch (IOException ex)
{
    Console.WriteLine("Giriş-çıxış xətası: " + ex.Message);
}
catch (UnauthorizedAccessException ex)
{
    Console.WriteLine("Fayla giriş yoxdur: " + ex.Message);
}
catch (Exception ex)
{
    Console.WriteLine("Naməlum xəta: " + ex);
}

Bəli-bəli, hər şey sadədir — tanış try-catch-dən istifadə edirik, amma asinxron metodda. Vacibdir ki, metod özü async açar sözü ilə olsun, yoxsa compiler hirslənəcək.

Vacib detal: await-ı harada qoymaq


Task<int> readTask = fs.ReadAsync(buffer, 0, buffer.Length);
// ... burada təsadüfən await və ya emal unutdunuz

Belə halda xəta baş verərsə, o, tapşırığın özünə (Task) düşəcək və siz onun haqqında nəticəni əldə etməyə çalışana qədər bilməyəcəksiniz — məsələn, await readTask ilə və ya Task.Exception vasitəsilə. Əgər ümumiyyətlə await-ı unutmusunuzsa — tapşırıq xəta ilə tamamlanacaq, sizə heç kim deməyəcək.

3. Niyə asinxron kod səhət emalı olmadan təhlükəlidir

Ssenari 1: «Fire and forget» — yeni başlayanların tələsi


FileStream fs = new FileStream("file.txt", FileMode.Open);
byte[] buffer = new byte[8000];
fs.ReadAsync(buffer, 0, buffer.Length);
// Sonra proqram öz həyatına davam edir

Oxuma əməliyyatı «paralel üzməyə» gedir və əgər o, xəta ilə bitərsə, heç bir catch onu tutmayacaq. İstisna tapşırığın içində gizlənəcək. Bu pattern-i «fire and forget» adlandırırlar və real tətbiqlərdə bu kritik səhətlərin itirilməsinə və resurs sızmasına səbəb ola bilər.

Ssenari 2: Asinxron metodlar await olmadan


Task t = MyAsyncMethod();
// ... burada nəsə edirsən, sonra t-i unudursan

MyAsyncMethod-in içində baş verən xətalar siz açıq şəkildə tapşırığı gözləməyənə qədər yuxarı qaldırılmayacaq (await t və ya t.Wait()).

4. Asinxron tapşırıqlardan gələn xətaları düzgün tutmaq

Strategiya 1: Həmişə await-dən istifadə et


try
{
    await SomeFileOperationAsync();
}
catch (Exception ex)
{
    Console.WriteLine("Bir şey səhv getdi: " + ex.Message);
}

Beləliklə, istisna birbaşa gözləmə yerində atılacaq və itkin düşməyəcək.

Strategiya 2: .ContinueWith vasitəsilə emal

Bir səbəbdən await-dən istifadə etmirsinizsə, ContinueWith ilə xəta handler-i əlavə etmək olar:


var task = fs.ReadAsync(buffer, 0, buffer.Length);
task.ContinueWith(t =>
{
    if (t.Exception != null)
        Console.WriteLine("Asinxron oxuma zamanı xəta: " + t.Exception.InnerException);
}, TaskContinuationOptions.OnlyOnFaulted);

Açığı desəm? Müasir C# tətbiqlərində belə yanaşma nadir hallarda istifadə olunur — async/await kodu daha sadə və təmiz edir.

Fayllarla asinxron işləyərkən mümkün istisnalar

5. Nümunə: Xətaların işlənməsi ilə asinxron oxuma

Bu loqikanı tətbiqimizə əlavə edək:


using System;
using System.IO;
using System.Threading.Tasks;

namespace FileAsyncDemo
{
    class Program
    {
        static async Task Main()
        {
            string path = "bigfile.txt";
            byte[] buffer = new byte[4096];

            try
            {
                using FileStream fs = new FileStream(path, FileMode.Open);
                int bytesRead = await fs.ReadAsync(buffer, 0, buffer.Length);
                Console.WriteLine($"Oxundu {bytesRead} bayt {path}-dən");
            }
            catch (FileNotFoundException ex)
            {
                Console.WriteLine("Fayl tapılmadı: " + ex.Message);
            }
            catch (UnauthorizedAccessException ex)
            {
                Console.WriteLine("Fayla giriş yoxdur: " + ex.Message);
            }
            catch (IOException ex)
            {
                Console.WriteLine("Oxuma/yazma xətası: " + ex.Message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Başqa xəta: " + ex.Message);
            }
        }
    }
}

Vacib qeyd

Əgər Main-də await-dən istifadə etmirsinizsə, və yalnız Task result = SomeAsyncMethod(); edirsinizsə — xətalar «səssiz» qalacaq və daha sonra, nəticəni əldə etməyə çalışdığınızda üzə çıxacaq.

6. Ən çox rast gəlinən səhvlər və "dərslər" xətaların emalında

await-ı asinxron metoda qoymağı unudurlar — xətalar vaxtında üzə çıxmır, proqram qeyri-müəyyən davranır.

Asinxron çağırışları try-catch-ə sarmırlar — tətbiq ilk nasazlıqda çökür.

Yalnız ümumi Exception-i emal edirlər, UnauthorizedAccessException və ya OperationCanceledException kimi spesifik istisnaları nəzərə almırlar — nəticədə pis diaqnostika olur.

«Fire and forget» tapşırıqlardan istifadə edir, amma xəta loglamasını etmirlər — istisnalar Task-in içində itir.

Tapşırığın bitdiyini uğurlu sayırlar. Nəticəni açıqca gözləmək (await) və istisnaları emal etmək lazımdır.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION