Boru hatları bellek kullanımını nasıl sınırlar?


36

Brian Kernighan bu videoda Bell Labs'ın küçük dillere / programlara yönelik hafıza kısıtlamalarına dayanan cazibesini anlatıyor.

Büyük bir makine 64 k-bayt - K, M veya G değil - ve bu da herhangi bir programın çok büyük olamayacağı anlamına geliyordu ve bu nedenle küçük programlar ve daha sonra boru mekanizması yazmak için doğal bir eğilim vardı. Temelde girdi çıkış yönlendirmesi, bir programın diğerine bağlanmasını mümkün kıldı.

Ancak bunun, programlar arasında iletmek için verilerin RAM'de saklanması gerektiğini göz önüne alarak bunun bellek kullanımını nasıl sınırlayabileceğini anlamıyorum.

Gönderen Vikipedi :

Unix benzeri sistemlerin çoğunda , bir boru hattının tüm süreçleri aynı anda başlatılır [benimkinin vurgusu], akışları uygun şekilde bağlanmış ve programlayıcı tarafından makinede çalışan diğer tüm işlemlerle birlikte yönetilmiş olarak. Bunun önemli bir yönü, Unix borularını diğer boru uygulamalarından ayırmak, tamponlama konseptidir: örneğin bir gönderme programı saniyede 5000 bayt üretebilir ve bir alıcı program sadece saniyede 100 bayt kabul edebilir, ancak veri kayboldu. Bunun yerine, gönderen programın çıktısı arabellekte tutulur. Alıcı program veri okumaya hazır olduğunda, boru hattındaki bir sonraki program tampondan okur. Linux'ta, arabellek boyutu 65536 bayttır (64KB). Gerekirse daha büyük arabellek sağlamak için bfr adlı bir açık kaynaklı üçüncü taraf filtresi kullanılabilir.

Bu beni daha da karıştırıyor, çünkü bu, küçük programların amacını tamamen ortadan kaldırıyor (belli bir ölçekte modüler olsalar bile).

İlk soruma çözüm olarak düşünebileceğim tek şey (bellek sınırlamaları boyut verilerine bağlı olarak sorunlu) büyük veri setlerinin basitçe o zamanlar hesaplanmadığı ve asıl sorun boru hatlarının çözmesi gereken şeydi. programların kendileri tarafından gerekli olan hafıza miktarı. Ancak Wikipedia'daki alıntı metne bakıldığında bile, bu beni şaşırtıyor: bir program bir anda uygulanmıyor.

Tüm bunlar, eğer geçici dosyalar kullanılırsa çok anlamlı olur, ancak boruların diske yazmadığını anladım (takas kullanılmadığı sürece).

Örnek:

sed 'simplesubstitution' file | sort | uniq > file2

sedDosyada okuyor ve satır satır tükürmek bana göre açık . Ancak sort, BK bağlantılı videoda belirtildiği gibi, tam bir duraklamadır, bu nedenle tüm verilerin hafızaya okunması gerekir (ya da öyle mi?), Sonra aktarılır uniq, hangisi (aklıma) bir tane olur bir anda-line programı. Fakat birinci ve ikinci boru arasında, tüm verilerin bellekte olması gerekir, değil mi?


1
unless swap is usedtakas her zaman yeterli RAM olmadığında kullanılır
edc65

Yanıtlar:


44

Verilerin RAM'de saklanması gerekmez. Borular, okuyucular orada değilse veya devam edemiyorsa, yazarlarını engeller; Linux altında (ve diğer uygulamaların çoğunda, hayal ediyorum) bazı tamponlamalar var ancak bu gerekli değil. Mtraceur ve JdeBP tarafından belirtildiği gibi ( ikincisinin cevabına bakınız) .), Unix tamponlu boruların ilk sürümleri diske ve bu da bellek kullanımının sınırlandırılmasına nasıl yardımcı olduklarını açıklar: bir işleme borusu, her biri disk tamponlarının sınırları dahilinde bir miktar veri işleyen küçük programlara ayrılabilir. Küçük programlar daha az hafıza alır ve boruların kullanılması işlemin seri hale getirilebileceği anlamına gelir: ilk program çalışır, çıktı tamponunu doldurur, askıya alınır, ikinci program programlanır, tamponu işler, vb. Unix sistemlerinden daha büyük olan ve paralel olarak birçok boru çalıştırabilir; ancak büyük miktarlarda veri için yine benzer bir etki göreceksiniz (ve bu tür bir tekniğin varyantları “büyük veri” işleme için kullanılıyor).

Örnekte

sed 'simplesubstitution' file | sort | uniq > file2

sedverileri filegerektiğinde okur , sonra sortokumaya hazır olduğu sürece yazar ; sorthazır değilse , yazma blokları. Veri sonunda bellekte gerçekten canlı, ama kendine özgü olduğu için sort, ve sort(o tür veri miktarı çok büyük geçici dosyaları kullanacağız) herhangi bir sorun ile başa çıkmak için hazırlanır.

Engelleme davranışını çalıştırarak görebilirsiniz.

strace seq 1000000 -1 1 | (sleep 120; sort -n)

Bu, oldukça fazla miktarda veri üretir ve ilk iki dakika boyunca hiçbir şey okumaya hazır olmayan bir işleme yönlendirir . Çok sayıda writeişlemin gerçekleştiğini göreceksiniz , ancak çok hızlı bir seqşekilde duracak ve iki dakika geçerek çekirdek tarafından engellenecektir ( writesistem çağrısı bekler).


13
Bu cevap, programların neden birçok küçük programa bölünmesinin hafıza kullanımından tasarruf edildiğini açıklamaktan da faydalanabilir: Bir programın çalışması için belleğe sığabilmesi için, ancak şu anda çalışan programa sahip olması gerekiyordu. Diğer tüm programlar Unix'in başlarında diske aktarılmış, bir seferde yalnızca bir program gerçek RAM'e değiştirilmişti. Böylece CPU, bir boruya yazacak (o zamanlar diskte olan ) bir programı çalıştıracak, bu programı değiştirecek ve borudan okuyan programın içinde değiştirecekti. Mantıksal olarak paralel bir montaj hattını artımlı seri hale getirilmiş uygulamaya dönüştürmenin zarif yolu.
mtraceur

6
@ malan: Birden fazla işlem başlatılabilir ve aynı anda çalıştırılabilir bir durumda olabilir. Ancak, en fazla bir işlem, herhangi bir zamanda her bir fiziksel CPU üzerinde gerçekleştirilebilir ve bu, her çalıştırılabilir işleme için CPU zamanının "dilimlerini" tahsis etmek, çekirdek işlem zamanlayıcısının işidir. Modern sistemlerde, çalıştırılabilir ancak şu anda zamanlanmamış bir işlem zaman dilimi bir sonraki dilimi beklerken genellikle bellekte saklı kalır, ancak çekirdeğin herhangi bir işlemin belleğini tekrar diske ve tekrar belleğe kaydetmesine izin verilir uygun bulur. (Burada bazı ayrıntıları el altında inceleyin.)
Daniel Pryden

5
Bir borunun her iki tarafındaki işlemler ortak rutinler gibi etkili bir şekilde davranabilir: bir taraf tamponu ve yazma bloklarını doldurana kadar yazar, bu noktada işlem geri kalan zaman dilimiyle hiçbir şey yapamaz ve bir IO bekleme modu. Ardından, işletim sistemi, zaman dilimi (ya da yaklaşmakta olan başka bir zaman dilimi) kalanını okuma tarafına verir; bu, arabellekte ve bir sonraki okuma bloklarında hiçbir şey kalmayıncaya kadar okur, bu noktada okuyucu işlemi geri kalanı ile hiçbir şey yapamaz onun zaman dilimi ve işletim sistemine geri döner. Veriler bir seferde bir arabellek değerinde olan borudan geçiyor.
Daniel Pryden

6
@ malan Programlara "aynı anda" kavramsal olarak tüm Unix sistemlerinde, sadece onları tam anlamıyla aynı anda RAM'de tutabilecekleri anlamına gelen modern çok işlemcili sistemlerde, tam anlamıyla aynı anda RAM'de tutuldukları anlamına gelir. hepsini aynı anda RAM’de tutmaz, bazıları diske gönderilir. Ayrıca, birçok bağlamdaki "belleğin" hem RAM alanın hem de diskteki alanın toplamı olan sanal bellek anlamına geldiğini unutmayın . Vikipedi, uygulama detaylarından ziyade konsepte odaklanıyor, çünkü özellikle Unix'in işleri gerçekten ne kadar eski yapmıştır?
mtraceur

2
@ malan Ayrıca, gördüğünüz çelişki "bellek" nin iki farklı anlamından (RAM - RAM + takas) geliyor. Sadece donanım RAM'inden bahsediyordum ve bu bağlamda, sadece şu anda CPU tarafından yürütülen kodun RAM'e sığması gerekiyordu (bu, Kernighan'ın bahsettiği kararları etkileyen şeydi) ve tüm programlar mantıksal olarak yürütülürken OS tarafından verilen bir zamanda (zaman dilimlemede sağlanan soyut seviyede) bir programın, diskteki takas alanını içeren tüm sanal belleğe sığması gerekir.
mtraceur

34

Ancak bunun, programlar arasında iletmek için verilerin RAM'de saklanması gerektiğini göz önüne alarak bunun bellek kullanımını nasıl sınırlayabileceğini anlamıyorum.

Bu senin temel hatan. Unix'in ilk sürümleri RAM'da boru verisi içermiyordu. Onları diskte sakladılar. Borular, i-düğümlere sahipti; boru cihazını gösteren bir disk cihazında . Sistem yöneticisi /etc/config, hangi diskin hangi cildin hangi cihaza, hangi cildin hangi cihaza ait olduğunu ve hangi cüruf cihaza ait olduğunu belirtmek için adlandırılmış bir program yürüttü .

Bekleyen verilerin miktarı, yalnızca diskteki i-düğümünün doğrudan bloklarının depolanması için kullanılmasından kaynaklanıyordu. Bu mekanizma kodu daha basit hale getirmiştir, çünkü aynı algoritma, normal bir dosyayı okumak için kullanılan bir borudan okumak için kullanılırken, boruların aranamadığı ve tamponun dairesel olması nedeniyle ortaya çıkan bazı değişiklikler ile kullanılmıştır.

Bu mekanizma, 1980'lerin ortalarından ortalarına kadar başkaları tarafından değiştirildi. SCO XENIX, i-düğümleri çekirdek içi tamponlarla değiştiren "Yüksek Performanslı Boru Sistemi" ni kazandı. 4BSD, isimsiz boruları soket çiftlerine dönüştürdü. AT&T STREAMS mekanizmasını kullanarak boruları yeniden uyguladı.

Ve elbette, sortprogram sınırlı bir tür 32KiB girdi girişi (ya da 32KiB mevcut değilse ne kadar küçük bir bellek miktarının tahsis edebileceğini) gerçekleştirdi, sıralanan sonuçları, sonuçta elde etmek için harici olarak birleştirildiği ara stmX??dosyalara yazdı. /usr/tmp/çıktı.

daha fazla okuma

  • Steve D. Pate (1996). "Arası iletişim". UNIX Internals: Pratik Bir Yaklaşım . Addison-Wesley. ISBN 9780201877212.
  • Maurice J. Bach (1987). Msgstr "Dosya Sistemi için Sistem Çağrısı". Unix İşletim Sisteminin Tasarımı . Prentice-Hall. ISBN 0132017571.
  • Steven V. Earhart (1986). " config(1M)". Unix Programcı El Kitabı: 3. Sistem Yönetimi Olanakları . Holt, Rinehart ve Winston. ISBN 0030093139. s. 23-28.

1

Kısmen haklısın ama sadece kazayla .

Örneğinizde, tüm veriler gerçekten de "aralarında" borular arasında okunmuş olmalı, ancak bellekte (sanal bellek dahil) bulunmaması gerekir. Alışılmış uygulamalar, sortkısmi dosyalara geçici bağlantılar yaparak ve birleştirerek RAM'e sığmayan veri kümelerini sıralayabilir. Bununla birlikte, her bir öğeyi okumadan önce sıralı bir dizi çıktısı alamayacağınız belirli bir gerçektir. Bu oldukça açık. Bu yüzden evet, sortilk borudan her şeyi okuduktan (ve ne olursa olsun, kısmen de olsa geçici filtreleri sıraladıktan sonra) ikinci boruya çıkış yapmaya başlayabilir. Fakat hepsini RAM'de tutmak zorunda değil .

Bununla birlikte, bunun boruların nasıl çalıştığı ile ilgisi yoktur. Borular isimlendirilebilir (geleneksel olarak isimleri vardır). Bu, dosyalar gibi, dosya sisteminde bir konumdan başka bir şey ifade etmekten başka bir şey ifade etmez. Ve bu sadece bir zamanlar boruların ne olduğuydu, dosyalar (yazımlar fiziksel belleğin uygunluğunun izin verdiği kadar bir optimizasyon olarak birleştirildi).

Günümüzde, borular verinin kopyalandığı küçük, sonlu boyutlu bir çekirdek tamponudur, en azından kavramsal olarak gerçekleşir. Çekirdek bu konuda yardımcı olabilirse, kopyalar VM hileleri oynayarak elde edilir (örneğin, bir dosyadan pipo yapmak genellikle aynı sayfayı diğer işlemin okuması için kullanılabilir kılar, bu nedenle sonunda sadece bir okuma işlemi olur, iki kopya olmaz ve Zaten arabellek önbelleği tarafından zaten kullanılandan daha fazla bellek gerekiyor, bazı durumlarda da% 100 sıfır kopya alabilirsiniz.

Borular küçük ve sonlu boyuttalarsa, bu durum bilinmeyen (büyük olasılıkla) büyük miktarda veri için nasıl çalışabilir? Çok basit: Başka bir şey uymadığında, yazma işlemi tekrar oda gelene kadar engeller.

Birçok basit programın felsefesi, hafızanın çok az olduğu bir zamanlar en yararlıydı. Çünkü, her seferinde küçük adımlarla çalışabilirsiniz. Günümüzde, avantajlar, bazı ekstra esnekliklerin dışında, artık o kadar da büyük değil.
Bununla birlikte, borular çok verimli bir şekilde uygulanmaktadır (olması gerekiyordu!), Bu yüzden de dezavantajı yoktur ve iyi çalışan ve insanların alıştığı yerleşik bir şeydir, bu nedenle paradigmayı değiştirmeye gerek yoktur.


'Borular seçildi' derken (JdeBP bir 'boru cihazı' varmış gibi görünüyor ), bunun belirli bir zamanda kullanılabilecek boru sayısında bir sınır olduğu anlamına mı geliyor (yani, bir sınırın olduğu |komutta kaç kez kullanabilirsiniz ?
malan

2
Hiç böyle bir sınır görmedim ve teoride hiç bir zaman olduğunu sanmıyorum . Uygulamada, dosya adı olan her şeyin bir inode'a ihtiyacı vardır ve inode sayısı elbette sonludur. Bir sistemdeki fiziksel sayfaların sayısı gibi, başka bir şey yoksa. Her boru böylece modern sistemler, 4k atomik yazma garanti zorunluluk borularının sayısına sabit bir sınır koyar en azından kendi bir tam 4k sayfasında, olabilir. Fakat birkaç gigabayt RAM almayı düşünün ... pratik olarak, bu asla karşılaşamayacağınız bir limit. Bir terminale birkaç milyon boru
Damon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.