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ślnej en_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 /