2 puan yazan GN⁺ 2024-11-30 | 1 yorum | WhatsApp'ta paylaş

Pipe neden "takılıyor" gibi görünür: buffering

  • Sorunun açıklaması: Bir log dosyasında belirli bir çıktıyı bulmak için tail -f /some/log/file | grep thing1 | grep thing2 komutunu çalıştırdığınızda, log satırları yavaş ekleniyorsa çıktının görünmediği bir sorun yaşanabilir. Bu, pipe takılmış gibi görünse de gerçekte programın veriyi pipe'a yazmamasından kaynaklanır.

Buffering'in nedeni

  • Buffering'in nedeni: Programların veriyi bir pipe'a ya da dosyaya yazmadan önce buffer'laması yaygındır. Bunun nedeni performansı artırmak için tüm çıktıyı anında yazmak yerine, belli miktarda veriyi biriktirip tek seferde yazmaktır.
  • Örnek: grep thing1, 8KB veri toplayana kadar eşleşen veriyi tutabilir ve bu yüzden çıktı görünmeyebilir.

Terminale yazarken buffering yapılmaz

  • Terminal ile pipe arasındaki fark: grep, çıktı terminale gidiyorsa line buffering kullanır, pipe'a gidiyorsa block buffering kullanır. Buna isatty fonksiyonu üzerinden karar verilir.

Buffering yapan ve yapmayan komutlar

  • Buffering yapmayan komutlar: tail, cat, tee gibi komutlar buffering yapmaz.
  • Buffering yapan komutlar: grep, sed, awk, tcpdump, jq, tr, cut gibi komutlar buffering yapar; bazılarında belirli flag'lerle buffering devre dışı bırakılabilir.

Programlama dillerinde varsayılan çıktı buffering'i

  • Buffering yapan diller: C, Python, Ruby, Perl gibi diller varsayılan olarak çıktı buffering'i yapar ve bu bazı yöntemlerle devre dışı bırakılabilir.

Ctrl-C basıldığında buffer içeriğinin kaybolması

  • Sorunun açıklaması: Ctrl-C bastığınızda buffer'daki içerik kaybolur. Bunun nedeni önce SIGINT sinyalinin gönderilmesidir.
  • Çözüm: tcpdump sürecinin PID'sini bulup kill -TERM $PID çalıştırırsanız buffer flush edilebilir.

Dosyaya yönlendirmede de buffering olur

  • Dosyaya yönlendirme: Dosyaya redirect ederken de buffering olur, ancak Ctrl-C nedeniyle buffer kaybı yaşanmaz.

Buffering'den kaçınmanın çeşitli yolları

  • Çözüm 1: Hızlı biten bir program çalıştırmak.
  • Çözüm 2: grep için --line-buffered flag'ini kullanmak.
  • Çözüm 3: awk kullanmak.
  • Çözüm 4: stdbuf kullanmak.
  • Çözüm 5: unbuffer kullanmak.

Buffering'i devre dışı bırakmak için ortam değişkeni

  • Fikir: PYTHON_UNBUFFERED gibi standart bir ortam değişkeni olsa iyi olurdu. NO_BUFFER gibi bir değişken öneriliyor.

Atlanan içerikler

  • Atlanan konular: Line buffering ile tamamen unbuffered çalışma arasındaki fark, stderr ile stdout buffering farkı, işletim sisteminin TTY sürücüsü buffering'i gibi konular.

1 yorum

 
GN⁺ 2024-11-30
Hacker News yorumu
  • Arabelleğe alınan erişim, belirli bir bayt sayısına ya da süreye ulaşıldığında flush edilmelidir. Bu, donanım arayüzlerinde benzer sorunları çözmek için kullanılan yaygın bir yöntemdir

    • Kullanıcı alanında arabelleğe alma yapan kütüphaneler, veriyi ilk kez arabelleğe aldıklarında uygun bir zamanlayıcı ayarlamalıdır
    • Zaman aşımı parametresinin argüman olarak verilmesi ya da insan zaman ölçeğinden biraz daha düşük, bant genişliği/eşik değeriyle orantılı veya flush ek yüküyle orantılı olması iyi olur
    • Hem yazma hem okuma için geçerlidir ve veri kanalına göre değişebilir
  • Sistem genelinde CPU boşa çıktığında tüm arabellekleri flush etmek isterim

    • Arabelleğe alma genellikle CPU tasarrufu sağlayan bir tekniktir
    • CPU boşa çıktığında tüm süreçlere "arabellekleri flush edin" sinyali gönderilmelidir
  • 20 yıldan uzun süredir NIX sistemleriyle uğraşıyorum ama arabelleğe alma sorunlarını hep unutuyorum

  • 35 yıldan uzun süredir Unix kullanıyorum ama arabelleğe almanın nasıl çalıştığını hiçbir zaman tam olarak anlamamıştım. Bu açıklama faydalı oldu

  • "Unbuffered" ile "line buffering" karıştırılıyor

    • Unbuffered performansı düşürebilir ve birden fazla kaynak aynı pipe'a yazdığında hatalı çıktı üretebilir
    • Line buffering terminalde varsayılandır ve pipe için uygundur
  • Arabellekler var çünkü ekrana çıktı basmak, arabelleğe yazmaktan görece çok daha yavaştır

    • UART ile çalışırken sık görülen bir sorundur ve çeşitli çözümleri vardır
    • Özel karakter kullanımı, uzunluk tabanlı yaklaşım, zaman tabanlı yaklaşım gibi farklı yöntemler vardır
  • Ctrl-C'ye basıldığında arabellek içeriği kaybolabilir

    • Çoğu programın SIGINT alındığında arabelleği flush edeceğini düşünürdüm
  • Unix'te arabelleğe alma sorunları yaşadım ve tüm 'awk' uygulamaları aynı şekilde davranmıyor

  • Donmuş pipe şakasını kaçırmış gibi hissediyorum