Buforowane vs niebuforowane IO

84

Dowiedziałem się, że domyślnie w programach operacje wejścia / wyjścia są buforowane, tj. Są one podawane z pamięci tymczasowej do programu żądającego. Rozumiem, że buforowanie poprawia wydajność we / wy (może poprzez redukcję wywołań systemowych). Widziałem przykłady wyłączania buforowania, jak setvbufw C. Jaka jest różnica między tymi dwoma trybami i kiedy jeden powinien być używany nad drugim?

sud03r
źródło

Odpowiedzi:

127

Chcesz mieć niebuforowane dane wyjściowe, gdy chcesz mieć pewność, że dane wyjściowe zostały zapisane przed kontynuowaniem. Jednym z przykładów jest błąd standardowy w bibliotece wykonawczej C - zwykle jest on domyślnie niebuforowany. Ponieważ błędy są (miejmy nadzieję) rzadkie, chcesz się o nich natychmiast dowiedzieć. Z drugiej strony standardowe wyjście jest buforowane po prostu dlatego, że zakłada się, że będzie przez nie przechodziło znacznie więcej danych.

Innym przykładem jest biblioteka rejestrowania. Jeśli komunikaty dziennika są przechowywane w buforach procesu, a proces zrzuca jądro, istnieje bardzo duża szansa, że ​​dane wyjściowe nigdy nie zostaną zapisane.

Ponadto zminimalizowane są nie tylko wywołania systemowe, ale także operacje wejścia / wyjścia dysku. Powiedzmy, że program czyta plik po jednym bajcie na raz. Z niebuforowanym wejściem wyjdziesz na (stosunkowo bardzo wolny) dysk dla każdego bajtu, mimo że prawdopodobnie i tak musi on odczytać cały blok (sam sprzęt dyskowy może mieć bufory, ale nadal wychodzisz do kontrolera dysku co będzie wolniejsze niż dostęp do pamięci).

Dzięki buforowaniu cały blok jest od razu wczytywany do bufora, a następnie poszczególne bajty są dostarczane z (niewiarygodnie szybkiego) obszaru bufora.

Pamiętaj, że buforowanie może przybierać różne formy, na przykład w poniższym przykładzie:

+-------------------+-------------------+
| Process A         | Process B         |
+-------------------+-------------------+
| C runtime library | C runtime library | C RTL buffers
+-------------------+-------------------+
|               OS caches               | Operating system buffers
+---------------------------------------+
|      Disk controller hardware cache   | Disk hardware buffers
+---------------------------------------+
|                   Disk                |
+---------------------------------------+
paxdiablo
źródło
Wykres jest cudowny. Warto wspomnieć, że FILEwewnętrzny bufor obiektu (strumienia) jest zupełnie inny niż fgetswymagany parametr bufora. To tylko zdezorientowało mnie na wiele godzin, zanim napisałem kod, aby to rozgryźć. QAQ
Rick
37

Potrzebujesz niebuforowanego wyjścia, gdy masz już dużą sekwencję bajtów gotowych do zapisu na dysku i chcesz uniknąć dodatkowej kopii w drugim buforze w środku.

Buforowane strumienie wyjściowe będą gromadzić wyniki zapisu w buforze pośrednim, wysyłając je do systemu plików systemu operacyjnego tylko wtedy, gdy zgromadzi się wystarczająca ilość danych (lub flush()zostanie zażądana). Zmniejsza to liczbę wywołań systemu plików. Ponieważ wywołania systemu plików mogą być drogie na większości platform (w porównaniu do krótkich memcpy), buforowane wyjście jest wygraną netto przy wykonywaniu dużej liczby małych zapisów. Wyjście niebuforowane jest generalnie lepsze, gdy masz już duże bufory do wysłania - kopiowanie do bufora pośredniego nie zmniejszy dalej liczby wywołań systemu operacyjnego i wprowadza dodatkową pracę.

Wyjście niebuforowane nie ma nic wspólnego z zapewnieniem, że dane dotrą na dysk; ta funkcjonalność jest zapewniana przez flush()buforowane i niebuforowane strumienie i działa na nich. Niebuforowane zapisy we / wy nie gwarantują, że dane dotrą na dysk fizyczny - system plików OS może przechowywać kopię danych w nieskończoność, nigdy nie zapisując ich na dysku, jeśli chce. Wymagane jest tylko zatwierdzenie go na dysku podczas wywołania flush(). (Pamiętaj, że close()zadzwoni flush()w twoim imieniu).

Aaron
źródło
Czy dzwonienie flush()zagwarantuje, że zostanie zapisany na dysku? Myślałem, że przekazałem go tylko do bufora dysku.
jrdioko
2
Musisz O_SYNCzapewnić, aby zagwarantować zapisy.
moshbear,
Niebuforowane operacje we / wy o zapisywaniu na dysk. Stąd termin niebuforowany (bez bufora pośredniego, ale bezpośrednio zapisywany na dysku) dla winapi, wywołujesz CreateFile z FILE_FLAG_NO_BUFFERING i FILE_FLAG_WRITE_THROUGH, aby upewnić się, że dane są bezpośrednio utrwalane po każdym zapisie. Dla innych systemów operacyjnych nie wiem.
Martin Kosicky