[GiM logo] gim.org.pl is down || odświeżony jogger (v.0.4) GiMa

zsh in uxterm Przez dłuższy czas używałem, zsh, później z powodu problemów z UTFem wróciłem do basha, jednakże ostatnio wróciłem do zsh, jednakże nie z powodów o kŧórych będzie mowa poniżej.
Jakiś czas temu porównywałem różne shelle i postanowiłem się podzielić wynikami.

Wszystkie testy były wykonane w konsoli, starałem się by każdy shell miał podobne (jeśli chodzi o obciążenie maszyny) warunki, w związku z czym większość usług była wyłączona. Każdy test był wykonany 5 razy, wyniki kolejnych testów zamieściłem w tabelkach.

Każdy pojedyńczy test zawierał pętlę składającą się z 150*100*30 = 4500000 kroków, ktoś może powiedzieć, że nikt nie pisze takich skryptów, jednak wiele razy spotkałem się ze skryptami, które mają ponad 10000 iteracji.
Testowałem basha (chyba nadal najpopularniejszy shell), ksh (znajomy ostatnio się wypowiadał, więc byłem ciekaw jak wypadnie), oraz zsh, którego używam.

Test 1 - $() + seq

Najpierw przetestujemy zwykłe przypisanie wartości do zmiennej, do konstrukcji pętli użyjemy (trendi i jezzi ostatnio ;)) operatora $() oraz instrukcji seq

  • z=0; s=`date +%s%N`;
  • for i in $( seq 1400 1550 ); do
  •   for j in $( seq 1 100 ); do
  •     for k in $( seq 1 30 ); do
  •       z=0;
  • done; done; done;
  • echo $z; k=`date +%s%N`; echo $(( $k - $s ))
shell #1 #2 #3 #4 #5 AVG
bash: 31.183 31.402 31.542 31.515 31.733 31.475
ksh: 22.724 22.737 22.755 22.766 22.737 22.744
zsh: 27.532 27.413 27.383 27.391 27.418 27.427

Test 2 - `` + seq

Podmieńmy operator $() na bardziej znany `` i zobaczmy co się stanie

  • z=0; s=`date +%s%N`;
  • for i in `seq 1400 1550`; do
  •   for j in `seq 1 100`; do
  •     for k in `seq 1 30`; do
  •       z=0;
  • done; done; done;
  • echo $z; k=`date +%s%N`; echo $(( $k - $s ))
shell #1 #2 #3 #4 #5 AVG
bash: 31.260 31.327 31.382 31.314 31.804 31.418
ksh: 24.060 24.037 24.088 23.992 23.960 24.027
zsh: 29.162 29.242 29.208 29.292 29.275 29.236

Jak widać ksh ponownie ma najlepszy czas, co świadczyć może o tym, że ma najmniejszy narzut przy wykonywaniu komend, warto wziąć to pod uwagę, jeśli nasz skrypt korzysta z poleceń, które nie są wbudowanymi poleceniami powłoki. Wygląda też na to, że operator $() jest szybszy niż ``

Test3 - likwidujemy seq'a

Po dłuższym zastanowieniu dochodzimy do wniosku: "Zaraz zaraz, przecież przy takiej (trójwarstwowej) konstrukcji pętli, seq jest wywoływany 30*100 razy!", zamieńmy więc seq'a na wbudowaną konstrukcję powłoki {liczba..druga_liczba} (darmowy tip: zarówno bash jak i ksh pozwalają także na konstrukcję {literka..druga_literka})

  • z=0; s=`date +%s%N`;
  • for i in {1400..1550}; do
  •   for j in {1..100}; do
  •     for k in {1..30}; do
  •       z=0;
  • done; done; done;
  • echo $z; k=`date +%s%N`; echo $(( $k - $s ))
shell #1 #2 #3 #4 #5 AVG
bash: 2.864 2.817 2.876 2.841 2.861 2.852
ksh: 1.152 1.250 1.266 1.199 1.161 1.206
zsh: 0.779 0.759 0.791 0.814 0.686 0.766

Jak widać, zysk jest conajmniej 10 krotny! (btw: bash vs. zsh 2.8/0.7 = 4.0)

Test 4 - wyrażenia arytmetyczne $(())

Nikt jednak nie robi w pętli (tylko) podstawienia, spróbujmy więc czegoś ciekawszego. Dawno dawno temu, za górami za lasami, mieszkała sobie komenda expr, jednak gdybyśmy chcieli jej użyć powodowałoby to 4500000 wywołań zewnętrznego polecenia... niezbyt dobry pomysł. Użyjemy więc operatora $(()), który pozwala na obliczenia stało i zmiennoprzecinkowe.

  • s=`date +%s%N`;
  • for i in {1400..1550}; do
  •   for j in {1..100}; do
  •     for k in {1..30}; do
  •       z=$(( $z + $j + $k - $i ));
  • done; done; done;
  • echo $z; k=`date +%s%N`; echo $(( $k - $s ))
shell #1 #2 #3 #4 #5 AVG
bash: 15.916 16.038 16.147 16.389 16.299 16.158
ksh: 7.028 7.096 7.027 7.082 7.041 7.055
zsh: 2.876 2.831 2.987 2.967 2.856 2.903

Jak widać, w tym teście ksh jest ponad dwukrotnie szybszy od basha, na zsh ponad dwukrotnie szybszy od zsh i pięciokrotnie szybszy od basha

Test 5 - mała poprawka

Kiedy pisałem ten artykuł, zauważyłem jeszcze jedną rzecz. Ponieważ w dość specyficzny sposób skonstruowałem wyrażenie: z = z +j + k - i możemy je zamienić na z += j + k - i i użyć operatora (()).

  • s=`date +%s%N`;
  • for i in {1400..1550}; do
  •   for j in {1..100}; do
  •     for k in {1..30}; do
  •       (( z += $j + $k - $i ));
  • done; done; done;
  • echo $z; k=`date +%s%N`; echo $(( $k - $s ))
shell #1 #2 #3 #4 #5 AVG
bash: 9.524 9.540 9.595 9.647 9.634 9.588
ksh: 4.929 4.901 5.025 4.944 4.999 4.960
zsh: 1.938 1.894 1.945 2.002 1.976 1.951

Jak widać, każdy shell przyśpieszył mniej więcej o 1/3.

Test 5b - sugestia peresa for ((a;b;c))

peres zasugerował w komentarzach, żeby spróbować jeszcze for'a C-podobnego, jednak wypada gorzej niż poprzednik, ergo for ((i=start; i<=stop; i++)) działa wolniej niż for i in {start..stop}

  • s=`date +%s%N`;
  • for ((i=1400; i<=1550; i++)); do
  •   for ((j=1; j<=100; j++)); do
  •     for ((k=1; k<=30; k++)); do
  •       (( z += $j + $k - $i ));
  • done; done; done;
  • echo $z; k=`date +%s%N`; echo $(( $k - $s ))
shell #1 #2 #3 #4 #5 AVG
bash: 13.149 13.210 13.221 13.269 13.292 13.228
ksh: 5.549 5.552 5.515 5.544 5.652 5.562
zsh: 2.319 2.330 2.394 2.395 2.397 2.367

Wnioski?

Ogólnie widać, że bash, w porównaniu z dwoma pozostałymi wypada kiepsko (zawsze twierdziłem, że to kobyła ;)). Oczywiście ciężko tu generalizować, gdyż to zaledwie kilka testów i testujących jedynie kilka rzeczy.
Ponadto głównym czynnikiem, który wpływa na czas wykonania się skryptów shellowych jest zazwyczaj czas w jakim wykonują się zewnętrzne programy, jednak jak widać zawsze można coś usprawnić. Tyle ode mnie.

catz: [kom.puterowe] [pro.gramowanie] [Techblog]
tagz: [bash] [ksh] [optymalizacja skryptów] [porównanie shelli] [zsh]
dnia środa, 27 czerwiec 2007, 191058 by Michał 'GiM' Spadliński

Komentarze:

Proszę wpisy pisane po angielsku komentować również w tym języku.

zapomniałem dodać, wszystkie skrypty, były jednolinijkowcami, tylko dla czytelności zostały podzielone na linijki ;)

dnia środa, 27 czerwiec 2007, 191229 by G

…a gdyby pętlę zmienić na:
for (( i = 1400; i <= 1550 ; i++ ));
…czy jakoś tak to szło?

dnia środa, 27 czerwiec 2007, 191641 by Michał Górny

zastanawiałem się nad tym, ale już mi się nie chciało, może później.

dnia środa, 27 czerwiec 2007, 192446 by G

Bardzo ciekawy artykuł (i przy okazji kilka ciekawych informacji na temat tego jak kodować). W weekend migruję na zsh. ;)

dnia środa, 27 czerwiec 2007, 221029 by Eluś

Przeczytałem, ale że nie programuję żadnych skryptów konsoli, to raczej włożę ten post do kategorii "przydasię..." ;)

BTW: "(btw: bash vs. zsh 2.8/0.7 = 0.4)" chyba zagalopowałeś się w stawianiu "0." ;)

Pozdrawiam

dnia czwartek, 28 czerwiec 2007, 082357 by MiB

Ciekawy wpis. Było by fajnie jakbyś jeszcze kiedyś napisał porównanie pod kątem funkcjonalności i możliwości danych powłok.

dnia czwartek, 28 czerwiec 2007, 092757 by deely

@deely: Funkcjonalność/możliwości? Ranking jest prosty i wygląda jakoś tak:
1. Zsh
2. Bash
...
4. Tcsh
...
8.ksh

dnia czwartek, 28 czerwiec 2007, 103415 by Hoppke

@Hoppke: Ranking rankingiem, ale bez argumentacji jest dla mnie bez znaczenia.

dnia czwartek, 28 czerwiec 2007, 111630 by deely

@deely: manual Zsh jest rozbity na kilka osobnych plików, bo razem ma chyba kilkadziesiąt kilo. Porównanie zestawu funkcji basha i zsh jest męczące.

Sam mogę podać kilka punktów, w których Zsh jest fajniejszy:
+ więcej funkcji w promptach (plus prawy prompt)
+ kolorowanie dopełnień (choć może w bashu już to dodali)
+ dopełnianie poleceń. Zsh-owe dopełnianie jest fajniejsze niż bash-completion
+ wygodniejszy w interaktywnej pracy, np. skrócony "which" (zamiast "which command" wystarczy "=command"), skrócone konstrukcje (zamiast "for i in foo;do bar;done" w Zsh można wpisać "for i in foo;bar"), edycja zmiennych środowiskowych inline ("vared"), lepiej działająca historia (bardziej konfigurowalne i skuteczniejsze niż w Bashu filtrowanie duplikatów - plik historii się nie rozrasta), ma więcej ciekawych funkcji które można pod klawisze sobie podpiąć...

No, dużo tego jest jeśli idzie o funkcjonalność.

Tcsh jest funkcjonalnie podobny do Basha 2 (i już sporo odstaje od Basha 3), niektórych rzeczy znanych z basha nie ma, inne ma za to lepiej zrobione, no ale używa składni csh, a nie sh. Więc jest na marginesie.

A ksh... ksh nie ma prawie nic, co by pomagało w pracy interaktywnej. W sam raz do skryptów, ale do pracy ręcznej lepiej wziąć zsh.

dnia czwartek, 28 czerwiec 2007, 112828 by Hoppke

@Hoppke: O, to już całkiem sensowne argumenty. Dzięki. Właściwie to próbowałem już przez pewien czas używać zsh, ale nigdy nie znalazłem czasu by skonfigurować go sobie według własnych upodobań. Wygląda na to, że w wolnej chwili dam mu jeszcze jedną szansę.

dnia czwartek, 28 czerwiec 2007, 113301 by deely

@MiB ups, to z rozpędu ;)
@Hopke, chyba ciut nie doceniasz ksh, fakt, to nie jest shell, który nadawałby się jakoś sensownie do pracy interaktywnej, tak na prawdę, to przecież implementacja języka skryptowego bardziej niż powłoka, co do zsh, to ja bym dodał jeszcze
+ rozbudowany system aliasów

dnia czwartek, 28 czerwiec 2007, 121431 by G

Zsh jest też na pewno mniej pamięciożerny, bo jest MODUŁOWY.

dnia poniedziałek, 02 lipiec 2007, 095426 by mariusz

Właśnie, jak skompilowany był zsh? Jak miał dużo modułów wkompilowanych to mógł wolniej się forkować itp.

dnia poniedziałek, 02 lipiec 2007, 095540 by mariusz

@Hoppke: ksh nie ma nic do pracy interaktynej? Hmm, mi tam set -o vi wystarcza.

dnia środa, 04 lipiec 2007, 082048 by Grzechu

Co do artykulu: jak autor wykonal pomiary? Na jakim sprzecie? czy ksh to bylo prawdziwe ksh czy pdksh ? Pytania i pytania.

dnia środa, 04 lipiec 2007, 082248 by Grzechu

@Grzechu: nie, nie pdksh, version sh (AT&T Labs Research) 1993-12-28 r
wszystkie testy były wykonane na tym samym sprzecie, jak pisałem, starałem się, by każdy shell miał te same warunki, co do samego sprzętu: 1.6 CoreDuo 2M cache, 1G ram, niestety w tej chwili nie mogę powiedzieć ile było wolnej w momencie przeprowadzania testów, interfejsy sieciowe downnięte, nie sądzę, by inne czynniki miały jakiś wpływ.

dnia środa, 04 lipiec 2007, 102045 by G

@GIM: mi nie chodzilo o sprzet, tylko jak mierzyles czas wykonania. Skryptem? jesli tak to skryptem w sh,bash,ksh,zsh,tcsh, whatever ? Moze bys prownal rowniez z jakims awk ???

dnia piątek, 06 lipiec 2007, 103652 by Grzechu

Oh, sorry, przeciez probka czasowa jest w skrypcie. ale dupa ze mnie. Tyle, ze to malo miarodajne.

dnia piątek, 06 lipiec 2007, 104420 by Grzechu

aha jeszcze cos zauwazylem: seq nie jest przenosny. na Solarisie nie ma n.p.

dnia czwartek, 12 lipiec 2007, 154639 by Grzechu

Powiem Ci, że tego nie widziałem (że seqa nie ma), Solaris to jednak zawsze jakiś ubogi był ;)

dnia czwartek, 12 lipiec 2007, 161943 by G

@wole jednak ubogi Solaris/OpenSolaris z ZFS i Dtrace niz nie wiadomo co ;-)

dnia czwartek, 12 lipiec 2007, 195812 by Grzechu

ksh do skryptów jest całkiem całkiem. Nie wiem czy pracowaliście z typeset + trap + inne.
Ma jednak kilka wad. Między innymi taką, że nie należy korzystać ze wszystkich funkcji dla zachowania przenośności, problemy z "interaktywnością", niekompatybilność konsolki z baszem co może razić userów z nawykami.
Zauważcie, że shell powinien być mały i nie mieć zależności - jeśli wymogi nie są właśnie takie to można użyć perla lub podobnych.
Jeśli o mnie chodzi to używam ksh do skryptów (jeśli można to lepiej użyć języka wyższego poziomu) a normalnie w konsolce bash lub zsh.

Pozdrawiam

dnia środa, 05 wrzesień 2007, 160724 by Adderek

hym twirdzisz ze zsh jest taki funkcjonalny . a czy ma takie bajery jak bash .
wbudowane wyrazenia regularne.
tj wdbudowana obsluga grep,sed.

dnia piątek, 04 styczeń 2008, 134807 by heidi

@heidi, owszem ma, man zshmodules, /zsh\/pcre, tylko nie wiem do końca, czy o coś takiego Ci chodzi.
zastanawiam się tylko, jak często używasz tego na codzień?

dnia piątek, 04 styczeń 2008, 142205 by GiM

uzywam w skryptach bo znacznie to przyspiesza dzialnie

dnia poniedziałek, 07 styczeń 2008, 153357 by heidi

Solaris ma seq, jak i parę innych funkcji, ale one są w zupełnie innym katalogu, i zazwyczaj doinstalowuje się to osobno.
a co do wyrażeń regularnych, wersja pcre jest znacznie lepsza (składnia perlowa), bo w wersji posix (tak jak w grep i innych) wielu rzeczy nie da się racjonalnie zrobić.

dnia czwartek, 20 listopad 2008, 063501 by znik

Tyle, że wersja pcre najczęściej jest wolniejsza...

dnia niedziela, 14 grudzień 2008, 122719 by GiM

..tożsamość..:
..meritum..:
..lokum..:
Wpisz kod:code