Próbuję zaktualizować znacznik czasu do bieżącego czasu we wszystkich plikach xml w moim katalogu (rekurencyjnie). Używam Mac OSX 10.8.5.
W przypadku około 300 000 plików następujące echo
polecenie zajmuje 10 sekund :
for file in `find . -name "*.xml"`; do echo >> $file; done
Jednak następujące touch
polecenie zajmuje 10 minut ! :
for file in `find . -name "*.xml"`; do touch $file; done
Dlaczego echo jest tutaj znacznie szybsze niż dotyk?
echo >> $file
doda nowy wiersz$file
i tym samym go zmodyfikuje. Zakładam, że będzie tak samo dla OS / X. Jeśli tego nie chcesz, użyjecho -n >> $file
.touch `find . -name "*.xml"`
byłoby nawet szybsze niż oba powyższe?>>$file
touch
co w ogóle wywoływać tyle razy?find . -name '*.xml' -print0 | xargs -0 touch
wywołujetouch
znacznie mniej razy (być może tylko raz). Działa na systemie Linux, powinien działać na systemie OS X.Odpowiedzi:
W bash
touch
jest zewnętrznym plikiem binarnym, aleecho
jest wbudowaną powłoką :Ponieważ
touch
jest to zewnętrzny plik binarny, a ty wywołujesztouch
raz na plik, powłoka musi utworzyć 300 000 instancjitouch
, co zajmuje dużo czasu.echo
jest jednak wbudowany w powłokę, a wykonanie wbudowanych powłok nie wymaga w ogóle rozwidlenia. Zamiast tego bieżąca powłoka wykonuje wszystkie operacje i nie są tworzone żadne procesy zewnętrzne; to jest powód, dla którego jest o wiele szybszy.Oto dwa profile operacji powłoki. Widać, że dużo czasu spędza się na klonowaniu nowych procesów podczas korzystania
touch
. Użycie/bin/echo
zamiast wbudowanej powłoki powinno dać znacznie bardziej porównywalny wynik.Korzystanie z dotyku
Za pomocą echa
źródło
Jak odpowiedzieli inni, użycie
echo
będzie szybsze niżtouch
wecho
przypadku polecenia, które jest powszechnie (choć nie musi) być wbudowane w powłokę. Używanie go zwalnia z narzutu jądra związanego z uruchamianiem rozpoczynania nowego procesu dla każdego otrzymanego plikutouch
.Należy jednak pamiętać, że najszybszym sposobem na osiągnięcie tego efektu jest nadal użycie
touch
, ale zamiast uruchamiania programu raz dla każdego pliku, można użyć-exec
opcji z,find
aby upewnić się, że jest uruchamiany tylko kilka razy. Takie podejście jest zwykle szybsze, ponieważ pozwala uniknąć narzutu związanego z pętlą powłoki:Użycie
+
(w przeciwieństwie do\;
) zfind ... -exec
uruchamia polecenie tylko raz, jeśli to możliwe, z każdym plikiem jako argumentem. Jeśli lista argumentów jest bardzo długa (jak ma to miejsce w przypadku 300 000 plików), wykonanych zostanie wiele uruchomień z listą argumentów o długości zbliżonej do limitu (ARG_MAX
w większości systemów).Kolejną zaletą tego podejścia jest to, że działa on solidnie z nazwami plików zawierającymi wszystkie znaki spacji, co nie ma miejsca w przypadku oryginalnej pętli.
źródło
+1
za wskazanie+
argumentu find . Myślę, że wiele osób nie jest tego świadomych (nie byłem).find
mają+
argument. Możesz uzyskać podobny efekt, przesyłając doxargs
.+
część jest wymagana przez POSIX, więc powinna być przenośna.-print0
nie jest.find
ma dostępną opcję, ale traktuje ją jak;
pod powierzchnią.echo
jest wbudowaną powłoką. Z drugiej stronytouch
jest zewnętrznym plikiem binarnym.Wbudowane powłoki są znacznie szybsze, ponieważ ładowanie programu nie wiąże się z żadnymi kosztami, tzn. Nie ma
fork
/ jestexec
zaangażowane. W związku z tym można zaobserwować znaczną różnicę czasu podczas wykonywania polecenia wbudowanego w porównaniu z poleceniem zewnętrznym wiele razy.Z tego powodu narzędzia takie
time
są dostępne jako wbudowane powłoki.Możesz uzyskać pełną listę wbudowanych powłok, mówiąc:
Jak wspomniano powyżej, użycie narzędzia w przeciwieństwie do wbudowanego powoduje znaczny spadek wydajności. Poniżej znajdują się statystyki czasu tworzenia ~ 9000 plików przy użyciu wbudowanego
echo
i narzędziaecho
:źródło
echo
na większości systemów jest plik binarny (dla mnie to jest/bin/echo
), więc możesz spróbować ponownie testów czasowych, używając go zamiast wbudowanego