Wszyscy mówią, że powinienem uczynić mój kod modułowym, ale czy nie jest to mniej wydajne, jeśli używam więcej wywołań metod niż mniejszych, ale większych metod? Jaka jest różnica w Javie, C lub C ++ pod tym względem?
Rozumiem, że łatwiej jest edytować, czytać i rozumieć, szczególnie w grupie. Czy zatem utrata czasu obliczeń jest nieznaczna w porównaniu z korzyściami związanymi z utrzymaniem czystości kodu?
java
c++
c
efficiency
fatsokol
źródło
źródło
Odpowiedzi:
Tak, to nie ma znaczenia.
Komputery to niestrudzone, prawie perfekcyjne silniki wykonawcze pracujące z prędkościami zupełnie nieporównywalnymi do mózgów. Chociaż istnieje wymierna ilość czasu, którą wywołanie funkcji wydłuża czas wykonywania programu, jest to niczym w porównaniu z dodatkowym czasem potrzebnym mózgowi następnej osoby związanej z kodem, gdy muszą one rozplątać nieczytelną procedurę nawet zacząć rozumieć, jak z tym pracować. Możesz wypróbować obliczenia żartu - załóż, że Twój kod musi zostać zachowany tylko raz , a to tylko dodaje pół godziny do czasu potrzebnego na pogodzenie się z kodem. Weź pod uwagę szybkość zegara procesora i oblicz: ile razy kod musiałby biec, żeby nawet marzyć o wyrównaniu?
Krótko mówiąc, litowanie się nad procesorem jest całkowicie błędne w 99,99% przypadków. W rzadkich pozostałych przypadkach użyj profilerów. Czy nie zakładają, że można na miejscu tych przypadków - nie można.
źródło
To zależy.
W lodowato wolnym świecie, jakim jest programowanie sieciowe, w którym wszystko dzieje się z ludzką prędkością, programowanie wymagające metod, w którym koszt wywołania metody jest porównywalny lub przekracza koszt przetwarzania wykonanego metodą, prawdopodobnie nie ma znaczenia .
W świecie programowania systemów wbudowanych i programów obsługi przerwań dla przerwań o dużej szybkości, z pewnością ma to znaczenie. W takim środowisku psują się zwykłe modele „dostępu do pamięci” i „procesora jest nieskończenie szybki”. Widziałem, co się dzieje, gdy zorientowany obiektowo programista na komputerze mainframe pisze swój pierwszy szybki program obsługi przerwań. To nie było ładne.
Kilka lat temu robiłem nierekurencyjne 8-kierunkowe barwienie kropelek łączności na zdjęciach FLIR w czasie rzeczywistym, na czym był wtedy przyzwoity procesor. W pierwszej próbie wykorzystano wywołanie podprogramu, a narzut wywołany podprogramem zjadł procesor żywy. (4 wywołania NA PIKSEL x 64 000 pikseli na klatkę x 30 klatek na sekundę = to rozgryzłeś). Druga próba zmieniła podprogram na makro C, bez utraty czytelności, i wszystko było jak róże.
Musisz ciężko patrzeć na to, co robisz i na środowisko, w którym będziesz to robić.
źródło
Po pierwsze: programy w wyższym języku są przeznaczone do czytania przez ludzi, a nie przez maszyny.
Napisz więc programy, aby je zrozumieć. Nie myśl o wydajności (jeśli poważnie masz problemy z wydajnością, profiluj swoją aplikację i zwiększ wydajność tam, gdzie jest to potrzebne).
Nawet jeśli prawdą jest, że wywołanie metody lub funkcji wymaga pewnego narzutu, nie ma to znaczenia. Dzisiaj kompilatory powinny być w stanie skompilować kod do wydajnego języka maszynowego, aby wygenerowany kod był wydajny dla architektury docelowej. Użyj przełączników optymalizacyjnych kompilatora, aby uzyskać wydajny kod.
źródło
Zazwyczaj, gdy w innym przypadku miałbyś dużą funkcję i podzieliłeś ją na wiele mniejszych, te mniejsze będą wstawiane, ponieważ jedyny minus inlinizacji (zbyt duże powtarzanie tych samych instrukcji) nie ma znaczenia w tym przypadku. Oznacza to, że Twój kod będzie działał tak, jakbyś napisał jedną dużą funkcję.
Jeśli z jakiegoś powodu nie są one wstawiane, a to staje się problemem z wydajnością, należy rozważyć ręczne wstawianie. Nie wszystkie aplikacje są połączonymi w sieć formularzami CRUD z ogromnymi wewnętrznymi opóźnieniami.
źródło
Prawdopodobnie nie ma kosztów obliczeniowych. Zwykle kompilatory / zespoły JIT z ostatnich 10-20 lat zajmują się funkcją wprowadzającą doskonale. W przypadku C / C ++ zwykle ogranicza się do funkcji „nieuniknionych” (tzn. Definicja kompilatora jest dostępna podczas kompilacji - to jest w nagłówku tego samego pliku), ale obecne techniki LTO przezwyciężyły to.
To, czy powinieneś poświęcić czas na optymalizację, zależy od obszaru, nad którym pracujesz. Jeśli masz do czynienia z „normalną” aplikacją, która przez większość czasu czekała na dane wejściowe - prawdopodobnie nie powinieneś się martwić optymalizacjami, chyba że aplikacja „poczuje się” powolna.
Nawet w takich przypadkach powinieneś skoncentrować się na wielu rzeczach przed wykonaniem mikrooptymalizacji:
O(n)
naO(log n)
może mieć znacznie większy wpływ niż wszystko, co można osiągnąć dzięki mikrooptymalizacji.List
kiedy potrzebujesz,HashSet
więc możeszO(n)
wyszukiwać, kiedy możeszO(1)
.Nawet jeśli zdecydujesz, że musisz przeprowadzić mikrooptymalizację (co praktycznie oznacza, że twoje oprogramowanie jest używane w HPC, wbudowane lub używane przez bardzo dużą liczbę osób - w przeciwnym razie dodatkowe koszty utrzymania przezwyciężyłyby koszty czasu komputera), potrzebujesz aby zidentyfikować punkty aktywne (jądra), które chcesz przyspieszyć. Ale prawdopodobnie powinieneś:
Jako ostatnia uwaga. Zwykle jedynym problemem związanym z wywołaniami metod są skoki pośrednie (metody wirtualne), które nie były przewidywane przez predyktor gałęzi (niestety skok pośredni jest trudnym przypadkiem). Jednak:
źródło
Moja odpowiedź prawdopodobnie nie rozszerzy się zbytnio na istniejące odpowiedzi, ale wydaje mi się, że moje dwa centy mogą być pomocne.
Po pierwsze; tak, w przypadku modułowości zwykle rezygnujesz z pewnego poziomu czasu wykonywania. Pisanie wszystkiego w kodzie asemblera da ci najlepszą prędkość. To mówi...
Znasz YouTube? Prawdopodobnie najbardziej istniejąca witryna o dużej przepustowości lub druga po Netflix? Piszą dużą część swojego kodu w języku Python, który jest wysoce modułowym językiem, który nie został zbudowany w celu uzyskania najwyższej wydajności.
Chodzi o to, że gdy coś idzie nie tak, a użytkownicy narzekają na powolne ładowanie filmów, nie ma wielu scenariuszy, w których ta powolność byłaby ostatecznie przypisywana niskiej szybkości wykonywania Pythona. Jednak szybka ponowna kompilacja Pythona i jego modułowa zdolność do wypróbowywania nowych rzeczy bez sprawdzania typu prawdopodobnie zapewnią inżynierom szybkie debugowanie tego, co się dzieje źle („Wow. Nasz nowy stażysta napisał pętlę wykonującą nowe zapytanie podrzędne SQL dla KAŻDEGO wyniku. ”) lub („ Och, Firefox wycofał ten stary format nagłówka pamięci podręcznej i utworzył bibliotekę Python, aby łatwo skonfigurować nowy ”)
W tym sensie, nawet pod względem czasu wykonania, język modułowy może być uważany za szybszy, ponieważ gdy znajdziesz swoje wąskie gardła, prawdopodobnie łatwiej będzie zreorganizować kod, aby działał w najlepszy sposób. Tak wielu inżynierów powie ci, że hity o wysokiej wydajności nie były tam, gdzie ich zdaniem byłyby (i w rzeczywistości rzeczy, które zoptymalizowali, nie były potrzebne; lub nawet nie działały tak, jak powinny!)
źródło
Tak i nie. Jak inni zauważyli program najpierw dla czytelności, potem dla wydajności. Istnieją jednak standardowe praktyki, które są zarówno czytelne, jak i efektywne. Większość kodu jest uruchamiana dość rzadko, a optymalizacja go i tak nie przyniesie większych korzyści.
Java może wstawiać mniejsze wywołania funkcji, więc nie ma powodu, aby unikać pisania funkcji. Optymalizatory zwykle działają lepiej z prostszym, łatwiejszym do odczytania kodem. Istnieją badania, które pokazują skróty, które teoretycznie powinny działać szybciej, w rzeczywistości dłużej. Kompilator JIT prawdopodobnie będzie działał lepiej, kod jest mniejszy, a często uruchamiane elementy można zidentyfikować i zoptymalizować. Nie próbowałem tego, ale spodziewałbym się, że jedna duża funkcja, która jest stosunkowo rzadko nazywana, aby się nie kompilować.
Prawdopodobnie nie dotyczy to Javy, ale w jednym badaniu stwierdzono, że większe funkcje faktycznie działały wolniej, ponieważ wymagały innego modelu odniesienia pamięci. To było specyficzne dla sprzętu i optymalizatora. W przypadku mniejszych modułów użyto instrukcji, które działały na stronie pamięci. Były one szybsze i mniejsze niż instrukcje wymagane, gdy funkcja nie pasowała do strony.
Są przypadki, w których warto zoptymalizować kod, ale na ogół trzeba profilować kod, aby ustalić, gdzie to jest. Uważam, że często nie jest to oczekiwany kod.
źródło