Testowałem szybkość Basha i Pythona, uruchamiając pętlę 1 miliard razy.
$ cat python.py
#!/bin/python
# python v3.5
i=0;
while i<=1000000000:
i=i+1;
Kod Bash:
$ cat bash2.sh
#!/bin/bash
# bash v4.3
i=0
while [[ $i -le 1000000000 ]]
do
let i++
done
Za pomocą time
polecenia dowiedziałem się, że kod Pythona zajmuje tylko 48 sekund, a kod Bash zajął ponad godzinę, zanim zabiłem skrypt.
Dlaczego tak jest? Spodziewałem się, że Bash będzie szybszy. Czy coś jest nie tak z moim skryptem, czy Bash jest naprawdę wolniejszy z tym skryptem?
echo echo hello >> $0
i uruchom go.Odpowiedzi:
Jest to znany błąd w bash; zobacz stronę podręcznika i wyszukaj „BŁĘDY”:
;)
Aby uzyskać doskonałe informacje na temat różnic koncepcyjnych między skryptami powłoki a innymi językami programowania, bardzo polecam przeczytanie:
Najważniejsze fragmenty:
Nie używaj dużych pętli w skryptach powłoki.
źródło
Pętle powłoki są powolne, a bash są najwolniejsze. Pociski nie są przeznaczone do wykonywania ciężkiej pracy w pętlach. Powłoki mają na celu uruchomienie kilku zewnętrznych, zoptymalizowanych procesów na partiach danych.
W każdym razie byłem ciekawy, jak porównują się pętle powłoki, więc zrobiłem mały test porównawczy:
( Szczegóły:
)
(Skrócone) wyniki (czas na iterację) to:
Z wyników:
Jeśli chcesz nieco szybszej pętli powłoki, to jeśli masz
[[
składnię i potrzebujesz szybkiej pętli powłoki, jesteś w zaawansowanej powłoce i masz również C-for for loop. Następnie użyj pętli C jak dla. Mogą być około 2 razy szybsze niżwhile [
pętle w tej samej skorupie.for (
pętlę około 2,7 µs na iteracjęwhile [
pętlę około 5,8 µs na iteracjęC dla pętli może być o 3-4 rzędy dziesiętne wielkości szybsze. (Słyszałem, że Torvaldowie kochają C).
Zoptymalizowana pętla C dla pętli jest 56500 razy szybsza niż
while [
pętla bash (najwolniejsza pętla powłoki) i 6750 razy szybsza niż pętla kshfor (
pętla (najszybsza pętla powłoki).Ponownie powolność powłok nie powinna mieć większego znaczenia, ponieważ typowym wzorem dla powłok jest odciążenie kilku procesów zewnętrznych, zoptymalizowanych programów.
Przy takim wzorcu powłoki często znacznie ułatwiają pisanie skryptów o wydajności przewyższającej skrypty Pythona (ostatnim razem, gdy sprawdzałem, tworzenie potoków procesu w Pythonie było dość niezdarne).
Kolejną rzeczą do rozważenia jest czas uruchamiania.
trwa 30 do 40 ms na moim komputerze, podczas gdy pociski trwają około 3 ms. Jeśli uruchamiasz wiele skryptów, szybko się to sumuje i możesz zrobić bardzo dużo w dodatkowych 27-37 ms, których uruchomienie zajmuje Python. Małe skrypty można ukończyć kilka razy w tym czasie.
(NodeJs jest prawdopodobnie najgorszym środowiskiem uruchomieniowym skryptów w tym dziale, ponieważ jego uruchomienie zajmuje około 100 ms (chociaż po jego uruchomieniu trudno byłoby znaleźć lepszą wydajność wśród języków skryptowych)).
źródło
ksh88
, AT & Tksh93
,pdksh
,mksh
...) jak jest sporo różnic między nimi. Nabash
, można określić wersję. Ostatnio poczynił pewne postępy (dotyczy to również innych powłok).from subprocess import *; p1=Popen(['echo', 'something'], stdout=PIPE); p2 = Popen(['grep', 'pattern'], stdin=p1.stdout, stdout=PIPE); Popen(['wc', '-c'], stdin=PIPE)
. Jest to rzeczywiście niezdarne, ale kodowaniepipeline
funkcji, która robi to za Ciebie dla dowolnej liczby procesów, nie powinno być trudnepipeline(['echo', 'something'], ['grep', 'patter'], ['wc', '-c'])
.Zrobiłem trochę testów i na moim systemie uruchomiłem następujące - żadne nie przyspieszyło rzędu wielkości, które byłyby potrzebne, aby być konkurencyjnym, ale możesz zrobić to szybciej:
Test 1: 18,233 s
test2: 20,45s
test3: 17,64s
test4: 26,69s
test5: 12,79s
Ważną częścią tego ostatniego jest eksport LC_ALL = C. Przekonałem się, że wiele operacji bash kończy się znacznie szybciej, jeśli jest używana, w szczególności jakakolwiek funkcja wyrażenia regularnego. Pokazuje także nieudokumentowaną składnię do używania {} i: jako no-op.
źródło
[[
jest o wiele szybsze niż[
. Nie wiedziałem, że LC_ALL = C (BTW nie trzeba go eksportować) zrobiło różnicę.[[
jest wbudowaną wersją bash i[
jest tak naprawdę/bin/[
, podobnie jak/bin/test
- programem zewnętrznym. I dlatego są wolniejsze.[
jest wbudowany we wszystkie popularne powłoki (trytype [
). Program zewnętrzny jest obecnie w większości nieużywany.Powłoka jest wydajna, jeśli używasz jej do tego, do czego została zaprojektowana (chociaż wydajność rzadko jest tym, czego szukasz w powłoce).
Powłoka to interpreter wiersza poleceń, przeznaczony jest do uruchamiania poleceń i współpracy ich z zadaniem.
Jeśli chcesz liczyć na 1000000000, należy powołać się na (jeden) polecenie, aby policzyć, jak
seq
,bc
,awk
lubpython
/perl
... 1000000000 Uruchamianie[[...]]
poleceń i 1000000000let
polecenia jest zobowiązany być strasznie nieskuteczny, zwłaszcza zbash
których powłoka jest najwolniejsza ze wszystkich.Pod tym względem powłoka będzie znacznie szybsza:
Chociaż oczywiście większość zadań jest wykonywana przez polecenia wywoływane przez powłokę, tak jak powinno być.
Teraz możesz oczywiście zrobić to samo z
python
:Ale tak naprawdę nie można tego robić,
python
ponieważpython
jest to przede wszystkim język programowania, a nie interpreter wiersza poleceń.Pamiętaj, że możesz zrobić:
Ale
python
tak naprawdę dzwoniłby do powłoki, aby zinterpretować ten wiersz poleceń!źródło
Odpowiedź: Bash jest znacznie wolniejszy niż Python.
Jednym małym przykładem jest post na blogu Wydajność kilku języków .
źródło
Nie ma nic złego (oprócz twoich oczekiwań), ponieważ Python jest naprawdę dość szybki dla nieskompilowanego języka, patrz https://wiki.python.org/moin/PythonSpeed
źródło
Oprócz komentarzy możesz trochę zoptymalizować kod , np
Ten kod powinien zająć trochę mniej czasu.
Ale oczywiście nie jest wystarczająco szybki, aby można go było faktycznie wykorzystać.
źródło
Zauważyłem dramatyczną różnicę w bash od użycia wyrażeń logicznie równoważnych „while” i „till”:
Nie dlatego, że tak naprawdę ma to ogromne znaczenie dla pytania, poza tym, że czasami małe różnice mogą mieć duże znaczenie, nawet jeśli spodziewalibyśmy się, że będą równoważne.
źródło
((i==900000))
.=
do zadania. To zwróci prawdę natychmiast. Nie nastąpi pętla.