Dlaczego narzędzie wc jest tak wolne?
Kiedy uruchamiam go na dużym pliku, zajmuje to około 20 razy dłużej niż md5sum:
MyDesktop:/tmp$ dd if=/dev/zero bs=1024k count=1024 of=/tmp/bigfile
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.687094 s, 1.6 GB/s
MyDesktop:/tmp$ time wc /tmp/bigfile
0 0 1073741824 /tmp/bigfile
real 0m45.969s
user 0m45.424s
sys 0m0.424s
MyDesktop:/tmp$ time md5sum /tmp/bigfile
cd573cfaace07e7949bc0c46028904ff /tmp/bigfile
real 0m2.520s
user 0m2.196s
sys 0m0.316s
To nie tylko dziwny stan krawędzi, ponieważ plik jest pełen zer, widzę tę samą różnicę w wydajności, nawet jeśli plik jest wypełniony losowymi danymi lub jest plikiem tekstowym.
(dotyczy wersji Ubuntu 13.04, 64-bitowej)
performance
wc
Jasio
źródło
źródło
Odpowiedzi:
Poszedłem więc do źródła i wygląda na to, że powolność polega na obsłudze znaków dwubajtowych. Zasadniczo, dla każdego wczytywanego znaku, musi on wywołać,
mbrtowc()
aby spróbować przekonwertować go na szeroki znak, a następnie ten szeroki znak jest testowany, aby sprawdzić, czy jest to separator słów, separator wierszy itp.Rzeczywiście, jeśli zmienię
LANG
zmienną ustawień narodowych z domyślnejen_US.UTF-8
(UTF-8 to zestaw znaków wielobajtowych) i ustawię ją na „C
” (prosty zestaw znaków jednobajtowych), będęwc
mógł zastosować optymalizacje jednobajtowe, co znacznie ją przyspieszy, zajmuje tylko około jednej czwartej tak długo jak wcześniej.Dodatkowo musi sprawdzać każdy znak tylko wtedy, gdy liczy się słowo (
-w
), długość linii (-L
) lub znak (-m
). Jeśli wykonuje tylko liczenie bajtów i / lub wierszy, może pominąć obsługę szerokich znaków, a następnie działa niezwykle szybko - szybciej niżmd5sum
.Pobiegłem go przez
gprof
, a funkcje, które są wykorzystywane do obsługi znaków wielobajtowych (mymbsinit()
,mymbrtowc()
,myiswprint()
itp) zajmują około 30% czasu wykonania samego, a kod podjęcie kroków przez bufor jest o wiele bardziej skomplikowane, ponieważ ma do obsługiwać kroki o zmiennej wielkości przez bufor dla znaków o zmiennej wielkości, a także wypychać częściowo ukończone znaki, które rozciągają bufor z powrotem na początek bufora, aby można go było obsłużyć następnym razem.Teraz, gdy wiem, czego szukać, znalazłem kilka postów o powolności utf-8 z niektórymi narzędziami:
/programming/13913014/grepping-a-huge-file-80gb-any-way-to-speed-it-up http://dtrace.org/blogs/brendan/2011/12/08 / 2000x-performance-win /
źródło
md5sum
nigdy nie pozwoli ci policzyć słowa iwc
nie obliczy skrótu md5 pliku! To tak, jakby pytać, dlaczego mój samochód jest tak wolny w porównaniu do mojej maszyny do pisania podczas pisania tekstu.wc
w rzeczywistości jest on związany z procesorem podczas przetwarzania znaków wielobajtowych.Tylko zgadnij, ale w pewnym sensie porównujesz jabłka do pomarańczy pod względem tego, co
wc
się robi, a comd5sum
się robi.Zadanie md5sum
Podczas
md5sum
przetwarzania pliku po prostu otwiera plik jako strumień, a następnie rozpoczyna przepływ strumienia przez funkcję sumy kontrolnej MD5, która wymaga bardzo mało pamięci. Zasadniczo jest związany z procesorem i dyskami we / wy.zadanie wc
Po
wc
uruchomieniu robi o wiele więcej niż tylko parsowanie pliku po znaku. Musi w rzeczywistości analizować strukturę pliku, linie na raz, ustalając, gdzie są granice między znakami i czy jest to granica słowa, czy nie.Przykład
Pomyśl o następujących ciągach i o tym, jak każdy z algorytmów musiałby się przez nie przemieszczać podczas ich analizy:
W przypadku MD5 trywialnie porusza się po tych ciągach po znaku. Na
wc
to musi zdecydować, co to słowo linia graniczna i śledzenie liczby wystąpień, że widzi.Dodatkowe dyskusje na temat wc
Znalazłem to wyzwanie kodowania z 2006 roku, które omawia implementację
wc
w .NET. Trudności są dość oczywiste, gdy spojrzysz na niektóre pseudo-kody, więc może to pomóc w wyjaśnieniu, dlaczegowc
wydaje się być o wiele wolniejszy niż inne operacje.źródło
wc
liczy wiele rzeczy podczas analizowania pliku. Liczy liczbę słów, linii i bajtów podczas analizy pliku. Przeczytaj stronę podręcznika man!wc
aby liczyć tylko linie, ogranicza jego wewnętrzną analizę, tak aby liczył tylko te rzeczy, czy tylko raportował wyniki linii, mimo że nadal liczy wszystko.