Dlaczego buforowanie w C++ jest ważne?

Dlaczego buforowanie w C++ jest ważne?

W przypadku operacji na plikach zapis do pamięci (RAM) jest zawsze szybszy niż bezpośredni zapis do pliku na dysku.

Dla ilustracji zdefiniujmy:

  • każda operacja zapisu IO do pliku na dysku kosztuje 1 ms
  • każda operacja zapisu IO do pliku na dysku przez sieć kosztuje 5 ms
  • każda operacja zapisu IO do pamięci kosztuje 0,5 ms

Powiedzmy, że musimy zapisać jakieś dane do pliku 100 razy.

Przypadek 1:Bezpośredni zapis do pliku na dysku

100 times x 1 ms = 100 ms

Przypadek 2:Bezpośredni zapis do pliku na dysku przez sieć

100 times x 5 ms = 500 ms

Przypadek 3:Buforowanie w pamięci przed zapisem do pliku na dysku

(100 times x 0.5 ms) + 1 ms = 51 ms

Przypadek 4:Buforowanie w pamięci przed zapisem do pliku na dysku przez sieć

(100 times x 0.5 ms) + 5 ms = 55 ms

Wniosek

Buforowanie w pamięci jest zawsze szybsze niż bezpośrednie działanie. Jednakże, jeśli system ma mało pamięci i musi zamienić się plikiem stronicowania, znowu będzie wolny. Dlatego musisz zrównoważyć operacje we/wy między pamięcią a dyskiem/siecią.


Głównym problemem związanym z zapisem na dysk jest to, że czas zapisu nie jest liniową funkcją liczby bajtów, ale afiniczną funkcją z dużą stałą.

W kategoriach obliczeniowych oznacza to, że w przypadku IO masz dobrą przepustowość (mniej niż pamięć, ale wciąż całkiem dobra), jednak masz niewielkie opóźnienie (trochę lepsze niż normalnie).

Jeśli spojrzysz na artykuły oceniające HDD lub SSD, zauważysz, że testy odczytu/zapisu są podzielone na dwie kategorie:

  • przepustowość w losowych odczytach
  • przepustowość w ciągłych odczytach

Ta ostatnia jest zwykle znacznie większa niż pierwsza.

Normalnie system operacyjny i biblioteka IO powinny to za ciebie abstrahować, ale jak zauważyłeś, jeśli twoja procedura jest intensywna we/wy, możesz zyskać, zwiększając rozmiar bufora. Jest to normalne, biblioteka jest generalnie dostosowana do wszelkiego rodzaju zastosowań i dlatego oferuje dobre pośrednie miejsce dla przeciętnych aplikacji. Jeśli Twoja aplikacja nie jest „przeciętna”, może nie działać tak szybko, jak by mogła.


Jakiego kompilatora/platformy używasz? Nie widzę tutaj znaczącej różnicy (RedHat, gcc 4.1.2); oba programy potrzebują 5-6 sekund na zakończenie (ale czas "użytkownika" to około 150 ms). Jeśli przekierowuję wyjście do pliku (przez powłokę), całkowity czas wynosi około 300 ms (więc większość z 6 sekund spędzam czekając, aż moja konsola dogoni program).

Innymi słowy, dane wyjściowe powinny być domyślnie buforowane, więc jestem ciekawy, dlaczego widzisz tak ogromne przyspieszenie.

3 stycznie powiązane uwagi:

  1. Twój program ma błąd „pojedynczy” polegający na tym, że drukujesz tylko 199999 razy zamiast podanych 200000 (albo zaczynaj od i = 0 lub zakończ na i <= 200000 )
  2. Miksujesz printf składnia z cout składnia podczas wyprowadzania liczby... poprawka jest wystarczająco oczywista.
  3. Wyłączanie sync_with_stdio daje dla mnie niewielkie przyspieszenie (około 5%) podczas wysyłania do konsoli, ale wpływ jest znikomy podczas przekierowywania do pliku. Jest to mikrooptymalizacja, której prawdopodobnie nie będziesz potrzebować w większości przypadków (IMHO).