Oceniam wyrażenie 6^6^6
za pomocą python
i bc
osobno.
Zawartość pliku python to print 6**6**6
. Kiedy wykonuję time python test.py
, otrzymuję wynik jako
real 0m0.067s
user 0m0.050s
sys 0m0.011s
Następnie uruchomiłem polecenie, time echo 6^6^6 | bc
które dało mi następujący wynik
real 0m0.205s
user 0m0.197s
sys 0m0.005s
Z tych wyników jasno wynika, że czas sys zajęty przez python i bc wynosił odpowiednio 11 ms i 5 ms. Komenda bc przewyższyła Pythona na poziomie czasu sys, ale jeśli chodzi o użytkownika i python w czasie rzeczywistym, była prawie 4 razy szybsza niż bc . Co mogło tam pójść. Nie nadałem żadnych priorytetów procesom jako takim. Próbuję zrozumieć tę sytuację.
python
performance
process-management
bc
ganessh
źródło
źródło
echo | bc
polega na uruchomieniu podpowłoki z powodu potoku - stąd prawdopodobnie pochodzi część twojego dodatkowego czasu użytkownika. Aby ten test był sprawiedliwy, skrypt Pythona powinien czytać ze standardowego wejścia, abyś mógłtime echo 6**6**6 | whatever.py
.echo 6^6^6 | time bc
.6**6**6
wyrażenie jest obliczane w czasie kompilacji . Ponieważ jednak uruchamiasz plik bezpośrednio zamiast importować go z modułu, nie powinno to mieć znaczenia. Aby zobaczyć różnicę wprowadzoną10**12345678
doa.py
pliku i spróbować zaimportować go z interaktywnego interpretera. Następnie zamknij interpreter, uruchom go ponownie i zaimportuja
ponownie. Za pierwszym razem powinno to zająć zauważalnie dużo czasu (ponieważ Python kompiluje moduł), a za drugim razem ładuje.pyc
, co powinno być natychmiastowe,Odpowiedzi:
Python importuje dużą liczbę plików podczas uruchamiania:
Każdy z nich wymaga jeszcze większej liczby prób otwarcia pliku Python, ponieważ istnieje wiele sposobów definiowania modułu:
Każde „próbowanie”, z wyjątkiem tych, które są wbudowane, wymaga wywołań systemu operacyjnego / systemu operacyjnego, a każde „importowanie” wydaje się wywoływać około 8 wiadomości „próbujących”. (Były sposoby na zmniejszenie tego za pomocą zipimport, a każda ścieżka w Twojej PYTHONPATH może wymagać innego połączenia.)
Oznacza to, że istnieje prawie 200 wywołań systemowych statystyki, zanim Python uruchomi się na moim komputerze, a „czas” przypisuje to do „sys”, a nie do „użytkownika”, ponieważ program użytkownika czeka w systemie na wykonanie różnych czynności.
Dla porównania, jak powiedział terdon, „bc” nie ma tak wysokich kosztów startowych. Patrząc na dane wyjściowe dtruss (mam komputer Mac; „strace” dla systemu operacyjnego opartego na Linuksie), widzę, że bc nie wykonuje własnych wywołań systemowych open () ani stat (), z wyjątkiem ładowania kilku wspólnych biblioteki są początkiem, co oczywiście robi również Python. Ponadto Python ma więcej plików do odczytania, zanim będzie gotowy do przetworzenia czegokolwiek.
Oczekiwanie na dysk jest wolne.
Możesz poznać koszt uruchomienia Pythona, wykonując:
Na mojej maszynie jest 0,032 sekundy, podczas gdy „drukuj 6 ** 6 ** 6” to 0,072 s, więc koszt uruchomienia to 1/2 całkowitego czasu, a obliczenie + konwersja na dziesiętne to druga połowa. Podczas:
zajmuje 0,005 sek., a „6 ^ 6 ^ 6” zajmuje 0,184 sek., więc potęgowanie bc jest ponad 4x wolniejsze niż Pythona, mimo że 7-krotnie szybciej jest zacząć.
źródło
Znalazłem fajną odpowiedź na SO wyjaśniającą różne pola:
Tak więc w twoim konkretnym przykładzie wersja Pythona jest szybsza pod względem faktycznego czasu potrzebnego do jej ukończenia. Jednak podejście python spędza więcej czasu w przestrzeni jądra, wykonując wywołania funkcji jądra.
bc
Komenda zasadniczo nie spędza czasu w przestrzeni jądra i wszystko to jest czas spędzony w przestrzeni użytkownika, przypuszczalnie działa wewnętrznybc
kod.Nie ma to dla ciebie żadnej różnicy, jedyne informacje, na których naprawdę Ci zależy,
real
to faktyczny czas, jaki upłynął między uruchomieniem polecenia a uzyskaniem jego wyniku.Należy również pamiętać, że te niewielkie różnice nie są stabilne, będą również zależeć od obciążenia systemu i będą się zmieniać za każdym razem, gdy uruchomisz polecenie:
źródło
Wyjaśnię to z innej perspektywy.
Szczerze
bc
mówiąc , ma tę zaletę, że nie musi niczego odczytywać z dysku i potrzebuje tylko swoich obiektów blob / binariów, podczas gdy Python musi zaimportować serię modułów + odczyt pliku. Więc twój test może być stronniczybc
. Aby go przetestować, powinieneś użyćbc -q file
gdziefile
zawiera:Zmiana tylko zmodyfikowała czas używania
echo
:Aby użyć pliku:
(będziesz musiał użyć metody Terdona, aby zauważyć większe różnice, ale przynajmniej wiemy, że są)
Teraz, z perspektywy Pythona, python musi czytać z dysku, kompilować i uruchamiać za każdym razem plik, a także ładować moduły jak wskazuje Andrew , co skraca czas wykonywania. Jeśli skompilujesz kod bajtowy skryptu python, zauważysz, że wykonanie kodu zajmuje o 50% mniej czasu:
opracowano:
Jak widać, istnieje kilka czynników, które mogą wpływać na czas wykonywania różnych narzędzi.
źródło
Miałem tę zaletę, że przeczytałem inne odpowiedzi. Na początek ludzie tacy jak ja, powinien wiedzieć, dlaczego mamy do czynienia z tak wielką liczbą całkowitą jest to, że zarówno
Python
ibc
zrobić prawym asocjacyjną ekspansję potęgowanie, co oznacza, że to nie6^36
my oceny, lecz6^46656
która jest znacznie większa. 1Używając wariantów następujących poleceń, możemy wyodrębnić średnią dla określonego elementu wyniku zarówno
time
słowa zarezerwowanego, jak i polecenia:Można przejść inną trasę i całkowicie usunąć plik z porównania. Możemy także porównać czas bc z czymś takim jak
dc
polecenie, ponieważ historycznie ten pierwszy jest „procesorem front-end” do drugiego. Nastąpiły następujące komendy:Zauważ, że
dc
polecenie ma lewy asocjatywny dla potęgowania. 2)Mamy kilka wyników dla
time
(bash) dla 1000 iteracji (w sekundach):bc
idc
oferują porównywalną wydajność w tym kontekście.Mniej dokładne 3 wyniki z
/usr/bin/time
np.time
Polecenia GNU (dokładność skali nie jest tutaj poprawna, ale wyniki są podobne):Zaletą
/usr/bin/time
jest to, że oferuje-v
opcję, która daje znacznie więcej informacji, które mogą być przydatne w końcu.Można również ocenić to wewnętrznie , aby porozmawiać z
timeit
modułem Python:To trochę szybciej niż to, co widzieliśmy wcześniej. Spróbujmy samego tłumacza:
To najszybszy jaki widziałem.
Jeśli ocenimy mniejszą potęgowanie
6^6
, to polecenie czasowe daje zaskakujące wyniki - używając tych samychfor
poleceń pętli, które teraz używamy:Więc przy mniejszej liczbie całkowitej
bc
jest nagle znacznie szybsze? Od ponownego uruchomienia systemu do drugiego uruchomienia nie ma znaczenia. Jednak jednocześnie, jeśli używamytimeit
Pythona, otrzymujemy:Są to mikrosekundy , a nie milisekundy, więc nie pasuje to do znacznie wolniejszych wyników w
for
pętli. Być może potrzebne są inne narzędzia do dalszego testowania, a jak wyjaśnili inni, tutaj jest więcej niż na pierwszy rzut oka. Wygląda na to, że Python był szybszy w scenariuszu pytania, ale nie jest jasne, czy można wyciągnąć wnioski poza tym ...1. Nie trzeba dodawać, że wykracza poza zakres czegoś takiego jak ekspansja arytmetyczna echa, tj.
echo $((6**6**6))
-bash
zdarza się również, że jest do tego słusznie asocjatywna, tj6^6^6 = 6^(6^6)
.2. Porównaj z tym:
6 6 ^ 6 ^ p
.3. Możliwe jest, że polecenie czasu GNU dostarcza więcej informacji, gdy jest uruchamiane w systemie BSD UNIX (dokument informacji o czasie GNU): Większość informacji wyświetlanych jako „czas” pochodzi z wywołania systemowego „wait3”. Liczby są tak dobre, jak te zwracane przez „wait3”. Wiele systemów nie mierzy wszystkich zasobów, o których „czas” może informować; zasoby te są zgłaszane jako zero. Systemy mierzące większość lub wszystkie zasoby oparte są na 4.2 lub 4.3BSD. Późniejsze wersje BSD używają innego kodu zarządzania pamięcią, który mierzy mniej zasobów. - W systemach, które nie mają wywołania „wait3”, które zwraca informacje o statusie, zamiast tego używane jest wywołanie systemowe „times”. Dostarcza znacznie mniej informacji niż „wait3”, więc w tych systemach „czas” zgłasza większość zasobów jako zero.
źródło