Wiele pytań i odpowiedzi na stronach C / C ++, w szczególności lub pośrednio, omawia problemy z wydajnością mikro (takie jak narzut funkcji pośredniej vs. bezpośredniej vs. wbudowanej) lub przy użyciu algorytmu O (N 2 ) vs O (N log N) na lista 100 przedmiotów.
Zawsze piszę bez obawy o wydajność mikroprocesorów i mało uwagi o wydajność makr, koncentrując się na łatwym w utrzymaniu, niezawodnym kodzie, chyba że wiem, że mam problem.
Moje pytanie brzmi: dlaczego tak bardzo zależy na dużej liczbie programistów? Czy to naprawdę problem dla większości programistów, czy po prostu miałem szczęście, że nie musiałem się tym zbytnio przejmować, czy też jestem złym programistą?
c++
c
optimization
code-organization
Tim Post
źródło
źródło
Odpowiedzi:
W praktyce wydajność rzadko stanowi problem, którym należy zarządzać na tym poziomie szczegółowości. Warto mieć oko na sytuację, jeśli wiesz, że będziesz przechowywać i manipulować ogromnymi ilościami danych, ale w przeciwnym razie masz rację i lepiej, utrzymując proste.
Jedną z najłatwiejszych pułapek, w które można wpaść - szczególnie w C i C ++, gdzie masz tak drobnoziarnistą kontrolę - jest optymalizacja zbyt wcześnie i na zbyt wysokim poziomie. Ogólnie zasada jest taka: A) nie optymalizuj, dopóki nie dowiesz się, że masz problem, i B) nie optymalizuj niczego, co nie okazało się problemem, używając profilera.
Następstwem B) jest to, że programiści notorycznie źle przewidują, gdzie występują wąskie gardła w ich wydajności, chociaż nawet w jednym, uważają, że są w tym dobrzy. Użyj profilera i zoptymalizuj wolne części lub zmień algorytmy, jeśli jedna sekcja kodu jest wywoływana zbyt wiele razy, aby powodować problemy.
źródło
./configure
zaryzykowałbym stwierdzenie, że do 75% czasu wykonywania można przeznaczyć na kod „inicjalizacji” w programach uruchamianych przez skrypt. 25-50% można nawet wydać na dynamiczne linkowanie.Myślę, że wszystko na twojej liście to mikrooptymalizacja, na którą ogólnie nie należy patrzeć, z wyjątkiem
myślę, że należy na to spojrzeć. Jasne, ta lista zawiera teraz 100 pozycji i wszystko jest szybkie jak na małe n , ale chciałbym się wkrótce założyć, że ten sam kod zostanie ponownie wykorzystany na kilka milionów list linii, a kod nadal będzie miał pracować rozsądnie.
Wybór właściwego algorytmu nigdy nie jest mikrooptymalizacją. Nigdy nie wiadomo, jakiego rodzaju dane będą używane przez ten sam kod przez dwa miesiące lub dwa lata później. W przeciwieństwie do „mikrooptymalizacji”, które są łatwe do zastosowania za pomocą profilera, zmiany algorytmów często wymagają znacznego przeprojektowania w celu skutecznego wykorzystania nowych algorytmów. (Np. Niektóre algorytmy wymagają już sortowania danych wejściowych, co może zmusić Cię do zmodyfikowania znacznych części aplikacji, aby zapewnić, że dane pozostaną posortowane)
źródło
Dawno, dawno temu, w mojej pierwszej pracy napisałem kod dla systemów wbudowanych. Systemy te używały mikroprocesorów 8086 i miały ograniczoną pamięć. Użyliśmy kompilatora Intel C. Jeden system, który zbudowałem, potrzebował dostępu do trójwymiarowej tablicy struktur. Zbudowałem go tak, jak powiedziała mi książka: zadzwoń do malloc dla 3 wymiarów, następnie przydziel wiersze dla następnego wymiaru, a następnie calloc dla węzłów końcowych.
To było dość skomplikowane (dla mnie w tym czasie), musiałem dopasować krzywą, kontrolować proces ANOVA i analizę chi-kwadrat. Nie było bibliotek, które zrobiłyby to za nas; musieliśmy to wszystko napisać i wszystko zmieścić na 8086.
System działał jak pies. Po szybkim profilowaniu odkryłem, że jednym z największych problemów był alokator. Aby rozwiązać problem, porzuciłem wszystkie połączenia z Malloc i sam zarządzałem pamięcią jednego dużego bloku pamięci.
W innym przypadku na tym samym zleceniu klient skarżył się na czas reakcji w swoim statystycznym systemie kontroli procesu. Zespół przede mną zaprojektował system „oprogramowania PLC”, w którym operatorzy mogą wykorzystywać logikę logiczną do łączenia sygnałów i wyłączników wyzwalających. Napisali go w uproszczonym języku, który dziś nazwalibyśmy „językiem specyficznym dla domeny”. jak pamiętam, to wyglądało
((A1 + B1) > 4) AND (C1 > C2)
i tak dalej.Oryginalny projekt analizował i interpretował ten ciąg za każdym razem, gdy był oceniany. Na naszym marnym procesorze zajmowało to dużo czasu, co oznaczało, że kontroler procesu nie mógł aktualizować się tak szybko, jak proces był uruchomiony.
Rzuciłem na to nowe spojrzenie i zdecydowałem, że mogę przełożyć tę logikę na kod asemblera w czasie wykonywania. Parsowałem go raz, a następnie za każdym razem, gdy był uruchamiany, aplikacja wywoływała funkcję generowaną dynamicznie. Chyba jak niektóre wirusy dzisiaj (ale tak naprawdę nie wiem). Rezultatem był 100-krotny wzrost wydajności, co sprawiło, że klient i mój szef byli naprawdę szczęśliwi.
Nowy kod nie był tak łatwy do utrzymania, ponieważ zbudowałem niestandardowy kompilator . Ale przewaga wydajności znacznie przewyższyła wadę konserwacji.
Niedawno pracowałem nad systemem, który musiał dynamicznie analizować plik XML. Większe pliki zajęłyby znacznie więcej czasu. Było to bardzo zależne od wydajności; zbyt wolne analizowanie spowoduje, że interfejs użytkownika stanie się całkowicie bezużyteczny.
Tego rodzaju rzeczy pojawiają się cały czas.
Więc .... czasami potrzebujesz łatwego w utrzymaniu, łatwego do napisania kodu. Czasami potrzebujesz szybkiego kodu. Kompromisem jest decyzja inżynierska, którą musisz podjąć w przypadku każdego projektu.
źródło
Jeśli przetwarzasz duże obrazy i iteruje się na każdym pikselu, poprawa wydajności może być krytyczna.
źródło
Pozwól, że powiem ci trochę, dlaczego kryje się za tym kultura.
Jeśli zbliżasz się do 40, a nie do 20 lat, a programujesz przez całe dorosłe lata, wtedy dorastałeś, gdy C ++ była naprawdę jedyną grą w mieście, aplikacje komputerowe były normą, a sprzęt był nadal znacznie opóźnione oprogramowanie pod względem przepustowości / wydajności.
Bardzo niewiele osób musi się dzisiaj martwić o te rzeczy.
Jednak 10 lat temu wciąż musiałeś się martwić, że twoje oprogramowanie zostanie pobrane przez modem 56kb i uruchomione na 5-letnim komputerze ... Czy pamiętasz, jak kiepskie były komputery w 1996 roku? Pomyśl o 4 GB dysku twardego, procesorze 200 MHz i 128 MB pamięci RAM ...
A serwery sprzed 10 lat? Serwer „następnej generacji” firmy Dell kosztował 2000 USD i był wyposażony w 2 (!) Procesory pentium 1 GHz, 2 Gb lub Ram oraz dysk twardy 20 Gb.
To była po prostu inna gra w piłkę i wszyscy ci „starsi” inżynierowie, którzy mają 10-letnie doświadczenie (faceci, którzy odpowiedzą na twoje pytania), obcinają zęby w tym środowisku.
źródło
jest tu już 10 odpowiedzi, a niektóre są naprawdę dobre, ale ponieważ to moje osobiste wkurzenie ...
przedwczesna optymalizacja, która a) zajmuje dużo więcej czasu niż proste rozwiązanie b) wprowadza więcej kodu, w którym proste rozwiązanie miałoby połowę wielkości i połowę złożoności ic) sprawia, że rzeczy są mniej czytelne, absolutnie należy unikać. Jeśli jednak programista ma wybór między użyciem std :: map lub std :: vector i wybiera niewłaściwą kolekcję z czystej ignorancji dla wydajności, która jest tak zła, jeśli nie gorsza niż przedwczesna optymalizacja. Co jeśli mógłbyś dzisiaj nieco zmienić swój kod, zachować czytelność, zachować tę samą złożoność, ale uczynić go bardziej wydajnym, zrobiłbyś to? Czy nazwałbyś to „przedwczesną optymalizacją”? Uważam, że wielu ludzi nie zastanawiałoby się nad tym w taki czy inny sposób.
Kiedyś byłem facetem, który doradzał „mikrooptymalizację”, która wymagała bardzo niewielkich zmian, i dostałem tę samą odpowiedź, co właśnie powiedziałeś: „nie powinieneś optymalizować zbyt wcześnie. Po prostu uruchommy to, a my to zmienimy później, jeśli wystąpi problem z wydajnością ". Naprawiliśmy kilka wydań. I tak, to był problem z wydajnością.
Chociaż wczesna optymalizacja może nie być dobra, myślę, że bardzo korzystne jest, gdy ludzie piszą kod ze zrozumieniem, co ten kod zrobi, i po prostu nie lekceważą żadnego pytania, które skutkuje zapisaniem O (x) jako „optymalizacja”. Jest teraz mnóstwo kodu, który możesz teraz napisać i przy odrobinie przemyślenia na temat wydajności unikniesz 80% problemów w przyszłości.
Weź również pod uwagę, że wiele problemów z wydajnością nie wydarzy się w twoim środowisku i nie od razu. Czasami będziesz mieć klienta, który przekroczy limit, lub inny programista zdecyduje się zbudować na twoim frameworku i zwiększyć liczbę obiektów 10-krotnie. Mając teraz na uwadze wydajność, możesz później uniknąć bardzo kosztownych zmian. A jeśli problem zostanie wykryty po oficjalnym wydaniu oprogramowania, nawet prosta poprawka stanie się 20 razy droższa.
Podsumowując, pamiętanie o wydajności przez cały czas pomaga rozwinąć dobre nawyki. Które są tak samo ważne, aby mieć tak czysty, jak najbardziej prosty i zorganizowany kod.
źródło
Podejrzewam, że wiele z tego, co widzisz, to prosty błąd próbkowania. Kiedy ludzie mają do czynienia z prostymi sytuacjami, piszą kod i to jest koniec rzeczy. Zadają pytania, gdy mają do czynienia z czymś stosunkowo trudnym, takim jak konieczność optymalizacji, szczególnie w sytuacji, gdy niekoniecznie jest oczywiste, że optymalizacja byłaby konieczna.
To powiedziawszy, niewątpliwie wiąże się to również z przedwczesną optymalizacją. Prawidłowo lub inaczej, C i C ++ mają reputację wydajności, która ma tendencję do przyciągania ludzi, którym zależy na wydajności - w tym tych, którzy mogą zoptymalizować zarówno przyjemność, jak i to, że jest naprawdę potrzebna.
źródło
i++
lub++i
operator ++
nie skompilował.Kilka innych odpowiedzi wspomina o systemach wbudowanych i chciałbym rozwinąć tę kwestię.
Istnieje wiele urządzeń zawierających tanie procesory, na przykład: kontroler kotła w domu lub prosty kalkulator kieszonkowy lub dziesiątki chipów w nowoczesnym samochodzie.
Aby zaoszczędzić pieniądze, mogą one mieć ilość pamięci flash (do przechowywania kodu) i pamięci RAM, które wydają się małe dla tych, którzy napisali kod tylko na komputery PC lub smartfony. Aby oszczędzać energię, mogą działać przy stosunkowo niskich częstotliwościach zegara.
Na przykład rodzina mikrokontrolerów STM32 korzysta z 24 MHz, 16 KB flash i 4 KB RAM , do 120 MHz, 1 MB flash i 128 KB RAM .
Pisząc kod dla takich układów, oszczędzasz dużo czasu, jeśli chcesz, aby Twój kod był jak najbardziej wydajny. Oczywiście przedwczesna optymalizacja pozostaje złym pomysłem; ale dzięki praktyce nauczysz się, jak często problemy mogą być rozwiązywane szybko i / lub przy minimalnych zasobach, i odpowiednio koduj.
źródło
Wśród nich jest zasadniczo języków niskopoziomowych, gdy jeden prowadzi do patologicznego przypadku spełnienia gdzie jeden szczegół, który nie ma znaczenia 99% czasu jest przyczyną z gardłem, ktoś rzeczywiście ma możliwość bezpośrednio obejść ten problem (w przeciwieństwie do większości innych Języki); ale oczywiście często jak to zrobić najskuteczniej nie jest od razu widoczne. Stąd połowa dziwnych / interesujących pytań dotyczących mikrooptymalizacji zadawanych tutaj.
Druga połowa pochodzi od ciekawskich, jak blisko mogą się zbliżyć do metalu. Są to zasadniczo języki niskiego poziomu, w końcu ...
źródło
Wydajność jest zawsze gorącym tematem w przypadku C i C ++. Jeśli chodzi o to, jak daleko należy się posunąć, zawsze można oszaleć do poziomu wbudowanego ASM lub użyć arytmetyki wskaźnika dla szybszej iteracji. Jest jednak moment, w którym poświęca się tyle czasu na optymalizację, że praca nad opracowaniem całego programu zostaje zatrzymana.
W rozwiązywaniu tych problemów występuje wydajność programisty i wydajność kodu. Które z nich, na których należy się skupić, zawsze wywołują ciekawe pytania. Ostatecznie najważniejsze pytanie brzmi, jak zauważalne jest dla użytkownika. Czy użytkownik będzie pracował z danymi, które tworzą tablice z setkami lub tysiącami elementów? W takim przypadku kodowanie szybkiego wykonania czynności może sprawić, że użytkownik narzeka, że standardowe operacje programu są powolne.
Jest też użytkownik, który będzie pracował z małymi ilościami danych. Kilka plików tu i tam, w których robienie rzeczy takich jak sortowanie i operacje na plikach nie będzie tak zauważalne dla użytkownika, jeśli korzystasz z funkcji wyższego poziomu, które ułatwiają utrzymanie ich kosztem pewnej wydajności.
To tylko mały przykład problemów, na które napotkasz. Inne sprawy obejmują sprzęt docelowego użytkownika. Będziesz musiał martwić się znacznie wydajnością, jeśli masz do czynienia z systemami wbudowanymi, a następnie, jeśli użytkownicy mają, powiedzmy, dwurdzeniowe maszyny z wieloma RAM.
źródło
Dlaczego programistów tak bardzo zależy? Są głupie pomysły wypełniające ich głowy, takie jak rozwiązywanie problemów z wydajnością, zanim zdadzą sobie sprawę, że je mają, i brak zrozumienia, kiedy zgadują .
To trudne, ponieważ z mojego doświadczenia wynika, że są pewne problemy z wydajnością, o których należy pomyśleć z wyprzedzeniem. Doświadczenie wymaga poznania ich.
To powiedziawszy, metoda, której używam jest podobna do twojej, ale nie taka sama:
Zacznij od najprostszego możliwego projektu. W szczególności struktura danych powinna być jak najbardziej znormalizowana i minimalna. W zakresie, w jakim ma nieuniknioną redundancję, należy unikać powiadomień, aby zachować spójność. Lepiej jest tolerować przejściową niespójność i naprawiać ją za pomocą okresowego procesu.
Gdy program jest w fazie rozwoju, okresowo dostosowuj wydajność, ponieważ problemy z wydajnością mogą się cicho wkradać. Metoda, której używam, polega na losowym wstrzymywaniu , ponieważ uważam, że jest najlepsza.
Oto przykład tego, co mam na myśli.
źródło
Szczerze mówiąc, zależy to od tego, jaki jest twój cel i czy programujesz profesjonalnie, czy jako hobby.
W dzisiejszych czasach nowoczesne komputery to naprawdę potężne maszyny. Bez względu na to, jakie podstawowe operacje zdecydujesz się wykonać, bez względu na to, czy próbujesz mikro zoptymalizować, czy nie, mogą sprawić, że ich praca będzie niezwykle szybka. Ale oczywiście, jeśli robisz coś innego (na przykład superkomputer dla dziedzin takich jak fizyka lub chemia), możesz zoptymalizować tyle, ile chcesz.
Pierwsi programiści MIT nie urodzili się, aby robić niesamowite rzeczy; Zaczęli upraszczać i zasilać istniejące algorytmy. Ich dumą było to, że 2 + 2 dają cztery w dwie sekundy mniej niż istniejący algorytm (to tylko przykład, masz pomysł). Ciągle próbowali używać mniejszej liczby kart dziurkaczy w swoich maszynach TI-83 w celu zwiększenia wydajności.
Ponadto, jeśli programujesz dla systemów wbudowanych, z pewnością musisz mieć oko na mikro wydajność. Nie chcesz mieć wolnego zegara cyfrowego, który tyka 5 sekund nanosekund wcześniej niż inny zegar cyfrowy.
Wreszcie, jeśli jesteś programistą hobbystycznym, optymalizacja najmniejszych szczegółów z pewnością nie zaszkodzi, nawet jeśli twój program jest szybki. To nie jest potrzebne, ale na pewno coś, nad czym możesz popracować i skorzystać z okazji, aby dowiedzieć się więcej. Jeśli pracujesz profesjonalnie przy oprogramowaniu, nie możesz wziąć tego luksusu, chyba że jest on niezwykle potrzebny.
źródło
Ostatnio byłem w podobnej sytuacji. Miałem szereg przedmiotów. W oczekiwanym przypadku na liście były dwa (!) Elementy, a nawet w najgorszym przypadku nie oczekuję więcej niż czterech, a może ośmiu.
Musiałem posortować tę listę. Okazuje się, że zamiana
std::sort
na sieć sortującą (zasadniczo wiele zagnieżdżonychif
) straciła duży procent czasu pracy (nie pamiętam liczby, ale było to około 10–20%). Jest to ogromna zaleta mikrooptymalizacji, a kod ma absolutnie kluczowe znaczenie dla wydajności.Oczywiście zrobiłem to dopiero po profilowaniu. Ale chodzi o to, że jeśli użyję języka, który jest tak niewygodny i skomplikowany jak C ++ (nie wspominając o irytująco złożonych zasadach rozwiązywania problemów z przeciążeniem), chcę czerpać pełne korzyści.
źródło
Skumulowane zużycie energii
Jest jedna odpowiedź, o której zawsze myślę, że brakuje jej w tej dyskusji i która trochę mnie niepokoi - skumulowane zużycie energii .
Pewnie, może nie ma to większego znaczenia, jeśli napiszesz swój program w języku zinterpretowanym na wysokim poziomie i pozwól mu działać w przeglądarce z kilkoma warstwami pośrednimi lub jeśli twoja pętla zajmie 0,01 sekundy zamiast 0,001 sekundy. Nikt nie zauważy, to znaczy, żaden indywidualny użytkownik nie zauważy.
Ale kiedy dziesiątki tysięcy, a nawet miliony użytkowników w niektórych przypadkach używają twojego kodu, cała ta dodatkowa nieefektywność sumuje się. Jeśli twoje narzędzie uniemożliwia procesorowi przejście w stan uśpienia tylko przez dziesięć sekund dziennie, a korzysta z niego milion użytkowników, nieefektywny algorytm zużył dodatkowe 140 kWh [1] dziennie.
Rzadko widzę to omawiane i myślę, że to smutne. Podejrzewam, że liczby te są znacznie gorsze w przypadku popularnych platform, takich jak Firefox i fantazyjne interaktywne aplikacje internetowe, i warto byłoby to zbadać.
[1] Właśnie to wymyśliłem, 10 milionów sekund razy 50 watów. Dokładna liczba zależy od wielu rzeczy.
źródło
Czasami po prostu masz algorytmy, które nie mogą być lepsze niż czas liniowy, dla którego wciąż istnieje duże zapotrzebowanie na wydajność.
Przykładem jest przetwarzanie wideo, w którym nie można rozjaśnić obrazu / klatki jako podstawowego przykładu bez zapętlania każdego piksela (przypuszczam, że można to zrobić za pomocą jakiejś hierarchicznej struktury wskazującej właściwości odziedziczone przez dzieci, które ostatecznie schodzą w dół na kafelki obrazu dla węzłów liści, ale wtedy odłożyłbyś wyższy koszt zapętlenia każdego piksela do renderera, a kod byłby prawdopodobnie trudniejszy w utrzymaniu niż nawet najbardziej zoptymalizowany filtr obrazu).
W mojej dziedzinie jest wiele takich przypadków. Zwykle robię bardziej pętle o złożoności liniowej, które muszą dotykać wszystkiego lub czytać wszystko niż te, które korzystają z jakiejkolwiek zaawansowanej struktury danych lub algorytmu. Nie ma pracy, którą można pominąć, gdy trzeba dotknąć wszystkiego. Więc w tym momencie, jeśli nieuchronnie masz do czynienia z liniową złożonością, musisz sprawić, aby praca wykonywana na iterację była tańsza i tańsza.
Tak więc w moim przypadku najważniejszymi i najczęstszymi optymalizacjami są często reprezentacje danych i układy pamięci, wielowątkowość i SIMD (zazwyczaj w tej kolejności, przy czym reprezentacja danych jest najważniejsza, ponieważ wpływa to na możliwość wykonania dwóch ostatnich). Nie mam tak wielu problemów, które rozwiązują drzewa, tabele skrótów, algorytmy sortowania i tego typu rzeczy. Mój codzienny kod brzmi bardziej jak „zrób coś dla każdego”.
Oczywiście jest to kolejny przypadek, aby porozmawiać o tym, kiedy konieczne są optymalizacje (a co ważniejsze, gdy nie są), mikro lub algorytmiczne. Ale w moim szczególnym przypadku, jeśli krytyczna ścieżka wykonania wymaga optymalizacji, przyrosty prędkości 10x + są często osiągane przez optymalizacje na poziomie mikro, takie jak wielowątkowość, SIMD i przestawianie układów pamięci i wzorców dostępu w celu poprawy lokalizacji odniesienia. Nieczęsto zdarza mi się zastępować sortowanie bąbelkowe sortowaniem introsortowym lub radix lub wykrywanie kolizji złożoności kwadratowej BVH tak bardzo, jak znaleźć punkty aktywne, które, powiedzmy, korzystają z podziału pola gorącego / zimnego.
Teraz w moim przypadku moja dziedzina jest tak krytyczna pod względem wydajności (raytracing, silniki fizyki itp.), Że powolny, ale doskonale poprawny raytracer, który zajmuje 10 godzin do renderowania obrazu, jest często uważany za bezużyteczny lub więcej niż szybki, który jest całkowicie interaktywny, ale generuje najbrzydsze obrazy z promieniami przeciekającymi wszędzie z powodu braku wodoszczelnego skrzyżowania promień / tri. Szybkość jest prawdopodobnie podstawową miarą jakości takiego oprogramowania, prawdopodobnie nawet bardziej niż poprawność do pewnego momentu (ponieważ „poprawność” jest rozmytym pomysłem z raytracowaniem, ponieważ wszystko jest przybliżone, o ile nie ulega awarii lub coś takiego). A kiedy tak jest, jeśli nie myślę o wydajności z góry, stwierdzam, że muszę zmienić kod na najdroższym poziomie projektowania, aby obsłużyć bardziej wydajne projekty. Więc jeśli nie
Gry to kolejna dziedzina podobna do mojej. Nie ma znaczenia, jak poprawna jest logika gry lub jak łatwa w utrzymaniu i genialnie zaprojektowana baza kodu, jeśli gra działa z prędkością 1 klatki na sekundę jak pokaz slajdów. W niektórych obszarach brak prędkości może faktycznie uczynić aplikację bezużyteczną dla użytkowników. W przeciwieństwie do gier, nie ma wystarczająco dobrych danych w obszarach takich jak raytracing. Użytkownicy zawsze chcą większej prędkości, a konkurencja przemysłowa przede wszystkim poszukuje szybszych rozwiązań. Nigdy nie będzie wystarczająco dobry, dopóki nie będzie w czasie rzeczywistym, w którym to momencie gry będą używać znaczników ścieżki. A potem prawdopodobnie nadal nie będzie wystarczająco dobry dla efektów wizualnych, ponieważ artyści mogą chcieć załadować miliardy wielokątów i przeprowadzić symulacje cząstek z samozderzeniem między miliardami cząstek przy 30+ FPS.
Teraz, jeśli jest to wygodne, mimo to nadal piszę około 90% kodu w języku skryptowym (Lua), nie martwiąc się o wydajność. Ale mam niezwykle dużą ilość kodu, który w rzeczywistości potrzebuje pętli od milionów do miliardów rzeczy, a kiedy przeglądasz miliony do miliardów rzeczy, zaczynasz zauważać epicką różnicę między naiwnym jednowątkowym kodem, który wywołuje brak pamięci podręcznej przy każdej iteracji, powiedzmy, wektorowy kod działający w równoległym dostępie do sąsiadujących bloków, w których żadne nieistotne dane nie są ładowane do linii pamięci podręcznej.
źródło
Jak już wspomniałeś, dbanie o problemy z mikroprocesorem jest bezwartościowe, zanim zdasz sobie sprawę z niektórych problemów naprawdę spowodowanych przez te problemy
źródło
Odpowiedź na to pytanie jest naprawdę niemożliwa. Większość tworzonego dziś oprogramowania to wewnętrzne strony internetowe i aplikacje LOB, a dla tego rodzaju programowania twoje rozumowanie jest całkiem poprawne. Z drugiej strony, jeśli piszesz coś w rodzaju sterownika urządzenia lub silnika gry, żadna optymalizacja nie jest „przedwczesna”; istnieje prawdopodobieństwo, że twoje oprogramowanie będzie działało na bardzo różnych systemach z różnymi ograniczeniami sprzętowymi. W takim przypadku należy zaprojektować pod kątem wydajności i upewnić się, że nie wybrano algorytmu nieoptymalnego.
źródło
Myślę, że problemem programisty, który tak bardzo dba o wydajność, jest to, że czasami w swoim życiu musiał pisać kod mikro-wykonawczy, być może bardzo pilnie, i uczył się, uczył się, uczył się, a na koniec znał wiele rzeczy i sztuczek.
A teraz trudno jest zapomnieć i bez wcześniejszego pomiaru, który pokazuje, że nie musi się martwić, jest po bezpiecznej stronie, używając szybkiego kodu.
Zawsze miło jest pokazać swoją głęboką wiedzę, umiejętności i sztuczki oraz ponownie wykorzystać to, czego się nauczyłeś. Sprawia, że czujesz się cenny, a czas poświęcasz na naukę, bo warto.
Czasami w życiu nauczyłem się, że przyrost prefiksu jest szybszy ...
... niż przyrost po postfiksie:
Teraz, jeśli MAX jest niski, nie będzie to miało znaczenia, a jeśli w pętli będzie prawdziwa praca, to też nie będzie miało znaczenia. Ale nie ma powodu, aby używać wersji Postfix, nawet jeśli dzisiejszy kompilator samodzielnie zoptymalizuje kod.
Być może osoby poszukujące wydajności potrzebują dodatkowego celu, oprócz napisania „działającego kodu”, takiego jak „działający i czytelny kod”, aby uzyskać wytyczne na wielkim morzu opcji.
źródło
Dbasz o swoje wymagania? Jeśli wydajność nie jest wymagana, nie przejmuj się nią. Poświęcenie na to znacznego czasu jest niekorzystne dla twojego pracodawcy.
Do pewnego stopnia wydajność jest zawsze wymagana. Jeśli możesz uderzyć, nie zastanawiając się nad tym, masz rację, nie myśląc o tym.
Osobiście najczęściej kieruję się wydajnością, gdy moje testy trwają długo. Jestem zbyt niecierpliwy, aby czekać 5 minut na ukończenie zestawu testów. Ale zwykle rozwiązuje się to, bawiąc się testami.
Istnieje duża liczba programistów, którzy są uzasadnieni, jak bardzo im zależy. Są duże liczby, które nie są. Porozmawiajmy o tych, którzy nie są.
Jedną z pierwszych rzeczy, których programiści uczą się w szkole, po tym, jak sprawić, by rzeczy faktycznie działały, jest duża notacja O. Wielu z nich właściwie uczy się lekcji, a tym samym właściwie skupia się na rzeczach, na które dramatycznie wpływa n. Inni nie rozumieją matematyki i zabierają lekcję, że gdy już zadziała, musi być szybka. Co gorsza, niektórzy z tych uczniów nigdy nie dowiadują się więcej o tym, co jest ważne z twoim kodem, oprócz tego, że działa i działa szybko. Nieodebrane lekcje: spraw, aby było czytelne, zaprojektuj je dobrze, nie baw się w to bez powodu.
Knuth miał rację: przedwczesna optymalizacja jest źródłem wszelkiego zła. Ale kiedy to zadziała, jaki jest następny krok? Szybko, prawda? NIE! Następny krok jest czytelny. Czytelny jest pierwszy, następny, środkowy i ostatni krok. Wiele osób, które przeprowadzają niepotrzebne optymalizacje wydajności, dokłada czytelności do magistrali.
Niektórzy nawet odczuwają przewrotny dreszczyk emocji z powodu nieczytelnego kodu. Musieli cierpieć, patrząc na trudny do zrozumienia kod stworzony przez innych, więc teraz ich kolej na zwrot.
Wiem to, bo kiedyś to robiłem. Kiedyś przerobiłem doskonale czytelną 5-liniową strukturę, aż do nieczytelnego jednoliniowego wyrażenia logicznego i z dumą wysłałem ją do mojego profesora, który spodziewał się zaimponować, ponieważ mogłem stworzyć coś tak zwartego i zastraszającego. Nie dostałem pochwały, na którą liczyłem.
Jeśli kod pozostaje czytelny, szybkie później jest łatwe. Dlatego Knuth podkreśla „przedwczesne”, a nie „niepotrzebne”. Ponieważ na pewno szybsze jest lepsze. Ale lepszy jest lepszy tylko w zależności od tego, co poświęcisz za to. Więc poczekaj, aż dowiesz się, jakiej wydajności naprawdę potrzebujesz, zanim poświęcisz się dla niej. Niechętnie poświęcajmy czytelność, ponieważ po jej zniknięciu trudno jest odzyskać.
Poza czytelnością jest cały świat projektowania oprogramowania. O czym jest ta strona. Niektórzy nie mają pojęcia, co zrobić w zakresie projektowania. Ponieważ nie potrafią zaimponować designem, robią nieczytelny bałagan, więc ludzie nie mogą powiedzieć, że nie mają pojęcia. Ponieważ nikt nigdy nie naprawia ich kodu, musi to być dobry kod, prawda?
Dla niektórych wydajność jest wymówką, aby zrobić wszystko, co chcą. Programiści mają dużą moc i autonomię. Zaufano im. Nie nadużywaj zaufania.
źródło