Dlaczego nazwany potok jest tak wolny, jak zapis do pliku?


18

Próbuję zrozumieć, jak działają potoki nazwane, aby usprawnić moją jednokierunkową komunikację międzyprocesową. Spodziewam się narzutu wynikającego z kopiowania danych do okrągłego bufora, który, jak sądzę, jest przechowywany w pamięci RAM, więc spodziewałem się, że potok będzie znacznie szybszy niż zapis do pliku (ponieważ pamięć RAM jest o rząd wielkości szybsza niż dysk).

Zamiast tego odkryłem, że nazwany potok (lub potok anonimowy) ma mniej więcej taką samą prędkość jak plik. To jest na pulpicie 3 GHz ze zwykłym dyskiem (nie półprzewodnikowym) z systemem Ubuntu Linux. Oto uproszczony program testowy w Pythonie:

import sys
import time
import random

megabyte = "".join(random.choice("abcdefghijklmnopqrstuvwxyz") for x in range(1024**2))

while True:
    before = time.time()
    sys.stdout.write(megabyte)
    after = time.time()
    sys.stderr.write("{} microseconds\n".format(1e6 * (after - before)))

Rurociągi prosto do /dev/null:

python test.py > /dev/null

daje 2,1 mikrosekundy (stała) na każdy megabajt.

Przesyłanie strumieniowe do pliku:

python test.py > /tmp/testout.txt

przeskakuje między 500 mikrosekund a 930 mikrosekund (większa wartość staje się bardziej powszechna w miarę powiększania się pliku - prawdopodobnie szuka miejsca na dysku).

Następnie nazwany potok:

mkfifo testpipe
cat testpipe > /dev/null &
python test.py > testpipe

daje 640 mikrosekund (stała) i potok bez nazwy:

python test.py | cat > /dev/null

daje również 650 mikrosekund (stała).

Czy ktoś może wyjaśnić, dlaczego prędkość potoku bardziej przypomina prędkość pliku niż /dev/nullprędkość? Czy może gdzieś mam przełącznik z napisem „przepuszczaj potoki przez bufor oparty na plikach, a nie bufor oparty na pamięci RAM” i czy mogę zmienić ten przełącznik? Czy może to być opcja jądra lub zmienna powłoki?

Inna interpretacja: załóżmy, że wyjście dyskowe przeskakuje między 500 a 930 mikrosekund, ponieważ 500 właśnie przesyła dane, a 930 faktycznie zapisuje. Zatem 500 ~ 640 dla rurociągów w obu przypadkach jest równoważne. Jednak zgodnie z tą interpretacją, dlaczego pomiędzy potokowaniem a faktycznym zapisem na dysk jest tylko czynnik dwa. Strony internetowe, które mówią o dyskach RAM, mówią, że dyski RAM są 50-200 razy szybsze niż dyski twarde.


1
Pisanie do /dev/nulljest w rzeczywistości dość tanie, podczas gdy pisanie gdziekolwiek indziej - czy to plik, FIFO, potok czy coś - jest znacznie droższe, ponieważ wymaga „dużego” wysiłku w obsłudze.
glglgl,

Odpowiedzi:


31

Nie widzisz żadnej poprawy wydajności, ponieważ tak naprawdę nie uderzasz dysku podczas korzystania z pliku - dane są w drodze na dysk, ale twój wątek wykonawczy nie musi czekać, aż się tam wyląduje, więc jesteś nie widząc kary prędkości uderzenia w dysk.

Jeśli chcesz poczekać, aż operacja dysku zakończy się, aby zobaczyć, o ile wolniej się to dzieje, zadzwoń sync()(jak zmieniać wersję Pythona, patrz tutaj ) - będziesz patrzył na dziesiątki tysięcy mikrosekund po prostu dla twojego dysku poszukaj kilka razy, aby zapisać plik (zakładając, że nie ma on szybkiej pamięci podręcznej zapisu, jak w przypadku kontrolera RAID).


Kiedy przestaniemy martwić się czasem wyszukiwania naszych urządzeń blokowych? :)
EEAA,

5
@EEAA Wszystkie dyski SSD przez cały czas.

1
Masz rację: przy sync()czasie zapisu na dysku średnio 74 000 mikrosekund. ( flush()Robiłem to w jednym wariancie mojego testu, nie zrobiłem tego). Więc moja interpretacja, że ​​500 ~ 640 mikrosekund na megabajt naprawdę jest narzutem, ma sens, dzięki.
Jim Pivarski,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.