CodeGym /Kurslar /C# SELF /Giriş-çıxış ( I/O ) ...

Giriş-çıxış ( I/O ) performans problemi

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

1. Niyə giriş-çıxış bu qədər yavaşdır?

Giriş-çıxışın (I/O) "yavaşlığı" həmişə maraq doğuran məsələdir. Kodumuz tez-tez məlumatları "gözləyir", hesablamadan daha çox vaxt sərf edir. Gəlin niyə "anbar"a gedib-gəlməyin mətbəxdə işləməyə nisbətən daha ləng olduğunu başa düşək.

Hardware məhdudiyyətləri (Hardware Limitations)

Sərt disklər (HDD). Mexanika: plitələr fırlanır, ox hərəkət edir. Axtarış vaxtı və fırlanma üçün vaxt lazımdır — bu yüksək latenziya yaradır.

Sərt vəziyyət yaddaşları (SSD). HDD-dən daha sürətlidir, mexanika yoxdur, amma yazma və hüceyrələrin aşınmasının idarə olunması əməliyyatları ani etmir.

Şəbəkə. Bant genişliyi və gecikmədən, routerlərdən və marşrutdan asılıdır. Giga-bit olsa belə, uzaq serverə cavab mili- və ya daha çox millisaniyə olur, CPU kimi nanosaniyələr deyil.

Əməliyyat sisteminin overhead-ları (OS Overhead)

  • İcazələrin yoxlanması. Prosesin faylı oxuma/yazma icazəsi varmı?
  • Fayl məlumatlarının tapılması. Fayl sistemi fragmentləri yığır.
  • Bufere və cache. OS performans üçün buffer və cache-ləri idarə edir.
  • Context switch. Proses I/O üçün gözləyərkən CPU dəyişir — bu da vaxtdır.

Böyük uçurum: CPU sürəti vs I/O sürəti

  • CPU əməliyyatı: 0.20.5 nanosaniyə
  • RAM-dən oxuma: 10100 nanosaniyə
  • SSD-dən oxuma: 50100 mikrosekund
  • HDD-dən oxuma: 510 millisekund
  • Şəbəkə sorğusu: 10100 millisekund və daha çox

Uçurum böyükdür. Hər xarakter üçün "kuryer çağırırsınızsa" (I/O), nə qədər sürətli "yığan" (CPU) olursunuzsa olun, yazmaq yavaş olacaq. Məlumatları bloklarla — cümlələr və abzaslar şəklində götürmək daha effektivdir.

2. Fayl daxilində: əslində nə baş verir?

Faylla işləyərkən əmrlər zənciri belə görünür:

flowchart TD
    A[Sizin C# kodunuz] --> B[.NET FileStream]
    B --> C[OS Windows / Linux / Mac]
    C --> D[Fayl sistemi: NTFS, ext4, APFS]
    D --> E[Cihaz drayveri]
    E --> F[Fiziki disk: HDD / SSD]
  • Sizin kodunuz məsələn, File.ReadAllText(path) çağırır.
  • .NET daxildə FileStream, buffer-lar və sistem çağırışlarından istifadə edir.
  • OS cache və növbələri idarə edir.
  • Fayl sistemi faylın bloklarını tapır.
  • Drayver cihazla əlaqə yaradır.
  • Yaddaş cihazı fiziki əməliyyatı yerinə yetirir.

Hər təbəqə overhead əlavə edir. Ən çox tıxac fiziki cihazda olur.

3. Nümunə: praktikada yavaş kod

Antipattern: faylı bir baytla oxumaq ReadByte() vasitəsilə.


// ❌ Faylı bayt-bayt oxumaq səmərəsizdir
using FileStream fs = new FileStream("bigfile.txt", FileMode.Open);
int currentByte;
while ((currentByte = fs.ReadByte()) != -1)
{
    // Bir baytla nəsə edirik
}

Niyə pisdir? Hər çağırış ReadByte() axına ayrıca müraciətdir. Böyük fayllarda belə çağırışların sayı milyonlarla ola bilər və sistem faydalı iş yerinə təşkilati xərclərə vaxt sərf edir.

Doğru — bloklarla oxumaq:


// ✅ Faylı böyük bloklarla effektiv oxuma
byte[] buffer = new byte[4096]; // 4 KB — standart buffer ölçüsü
int bytesRead;
using FileStream fs = new FileStream("bigfile.txt", FileMode.Open);
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
{
    // Alınan blok məlumatı emal edirik
}

Böyük porsiyalarla oxumaq OS və diskin cache və növbələri daha effektiv istifadə etməsinə imkan verir — icra vaxtı qatlarla azalır.

4. Real tətbiqlərə təsiri

İstifadəçi interfeysi (UI). Blok edən I/O pəncərəni "dondurur". Əhəmiyyətlidir ki, əməliyyatları fon/asanxronluğa çıxarasınız və əsas thradı bloklamayasınız.

Veb-serverlər və DB. Serverlər davamlı oxu/yazı əməliyyatları aparır; yavaş disk və ya şəbəkə bütün xidməti yavaşıda bilər. Buffering, connection pool və asin xron I/O throughput üçün açardır.

Big Data. Qiqabayt/terabayt səviyyəsində hər bir səmərəsizlik böyüyür. Blok ölçüləri, ardıcıl oxu və stream əsaslı emal məsələnin həllində rol oynayır.

Oyunlar. Səviyyələrin/asset-lərin uzun yüklənməsi — bu I/O-dir. Asset-ləri düzgün paketləmək və böyük chunk-larla oxumaq yüklənməni qısaldır.

5. Başlayanların tipik səhvləri

Tez-tez rastlanan səhv — böyük faylları sətr-sətr və ya bayt-bayt ReadByte ilə oxumaq və ya çox kiçik buffer (məsələn, 256 bayt) istifadə etmək. Sistemdə çağırışların sayı artır, performans düşür.

Digər sərhəd: böyük faylı tam oxumağa çalışıb File.ReadAllBytes istifadə etmək və nəticədə OutOfMemoryException almaq. "Qızıl orta" seçmək daha yaxşıdır: məntiqli bloklar (dəfələrlə 48 KB və daha böyük, yükləmə profilinə görə) və stream əsaslı emal.

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