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/null
prę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.
/dev/null
jest 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.Odpowiedzi:
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).źródło
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.