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
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
Sistem genelinde CPU boşa çıktığında tüm arabellekleri flush etmek isterim
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
Arabellekler var çünkü ekrana çıktı basmak, arabelleğe yazmaktan görece çok daha yavaştır
Ctrl-C'ye basıldığında arabellek içeriği kaybolabilir
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