Sync ve Async dosya I/O: throughput, ölçeklenebilirlik ve buffer boyutu
Gérald Barré, async/await serisinin bu ek yazısında dosya okuma senaryolarında "her zaman async kullan" tavsiyesinin yarısının doğru olduğunu benchmarklarla gösteriyor. Tek işlem gecikmesi önemliyse sync I/O daha hızlı çıkıyor; asıl fark eşzamanlı yük altında thread havuzunu meşgul etmemekte ortaya çıkıyor. Yazı ayrıca buffer boyutu ve FileOptions flag'lerinin sonuçları nasıl değiştirdiğini anlatıyor.
Kilit noktalar
- Sync I/O tek dosya ve gecikmeye duyarlı açılış yollarında genelde daha hızlı.
- Async I/O'nun kazancı ham hız değil, eşzamanlı yük altında thread havuzunun boş kalması.
- ReadAsync kullanıyorsanız stream'i FileOptions.Asynchronous ile açın, yoksa runtime yavaş yola düşebilir.
- Baştan sona sıralı okumalarda FileOptions.SequentialScan iyi bir ipucu; async ile birleştirilebilir.
- 64 KB civarı buffer çoğu senaryoda syscall yükü ile bellek baskısı arasında denge sunuyor.
- Mikrobenchmark yerine gerçek dosya boyutları ve eşzamanlılık seviyeleriyle ölçün.
Yazar, File.ReadAllBytes için sync ve async yollarını 4 KB'tan 16 MB'a kadar dosyalarda BenchmarkDotNet ile ölçüyor. 4 KB'ta sync ortalama 69,7 µs, async 103,97 µs; 16 MB'ta fark 6.326 µs'ye karşı 7.501 µs'ye çıkıyor ama oransal olarak daralıyor. Sonuç ideolojik değil: sync en hızlı tek işlem gecikmesini, async ise eşzamanlı yük altında thread kullanılabilirliğini hedefliyor.
Gerçek async davranışı için stream'in FileOptions.Asynchronous ile açılması gerekiyor; aksi halde runtime daha yavaş bir yola düşebiliyor. Sıralı okumalarda FileOptions.SequentialScan faydalı bir ipucu ve async ile birlikte kullanılabiliyor. 64 KB gibi orta-büyük bir buffer genelde iyi denge; çok büyük buffer'lar bellek baskısı yaratıyor. Uyarı: SequentialScan her zaman kazanç sağlamıyor.
Gerçek dünyada kullanımı
- Uygulama açılışında birkaç yapılandırma veya cache dosyasını hızlıca yükleyen masaüstü uygulaması.
- Yük altında yüzlerce dosya okuması yapan ASP.NET Core endpoint'i veya arka plan worker'ı.
- Sıralı olarak büyük log veya dışa aktarma dosyalarını tarayan bir toplu işlem.
- Dosya indirme yükleyen ve aynı anda thread havuzunu başka isteklere açık tutması gereken servis.
Neden önemli
Dosya I/O modelini iş yüküne göre seçmek, aynı kodun açılışta daha hızlı hissettirmesini ve yüksek eşzamanlılıkta thread açlığı yaşamamasını sağlıyor; buffer ve flag ayarları da ölçülebilir kazanç getiriyor.