Kiedy optymalizacja nie jest przedwczesna, a zatem nie jest zła?


75

„Przedwczesna optymalizacja jest źródłem wszelkiego zła” to coś, co prawie wszyscy z nas słyszeli / czytali. Co mnie ciekawi, jaki rodzaj optymalizacji nie jest przedwczesny, tj. Na każdym etapie tworzenia oprogramowania (projektowanie na wysokim poziomie, szczegółowe projektowanie, wdrażanie na wysokim poziomie, szczegółowe wdrażanie itp.) Jaki zakres optymalizacji możemy rozważyć bez przechodzenia na ciemną stronę.



Odpowiedzi:


116

Kiedy bazujesz na doświadczeniu? Nie zło „Za każdym razem, gdy robiliśmy X, doświadczaliśmy brutalnego spadku wydajności. Tym razem planujemy zoptymalizować lub całkowicie uniknąć X”.

Kiedy jest względnie bezbolesny? Nie zło „Wdrożenie tego jako Foo lub Bar zajmie tyle samo pracy, ale teoretycznie Bar powinien być o wiele bardziej wydajny. Zabierzmy to”.

Kiedy unikasz gównianych algorytmów, które skalują się strasznie? Nie zło „Nasz technolog mówi, że nasz proponowany algorytm wyboru ścieżki działa w czasie czynnikowym; nie jestem pewien, co to oznacza, ale sugeruje, abyśmy popełnili seppuku, nawet by to rozważyć. Zastanówmy się nad czymś innym.”

Zło pochodzi z spędzania dużo czasu i energii na rozwiązywaniu problemów, o których istnieniu nie wiadomo. Kiedy problemy na pewno istnieją lub gdy fantomowe problemy psudo można rozwiązać tanio, zło znika.


Steve314 i Matthieu M. podnoszą punkty w komentarzach, które należy wziąć pod uwagę. Zasadniczo niektóre odmiany „bezbolesnych” optymalizacji po prostu nie są tego warte, ponieważ oferowane przez nich trywialne ulepszenia wydajności nie są warte zaciemnienia kodu, są duplikatami rozszerzeń, które kompilator już wykonuje, lub obu tych elementów. Zobacz komentarze, aby zapoznać się z przykładami zbyt sprytnych usprawnień o połowę.


22
Czasami łatwe rozwiązanie problemu fantomowego jest wciąż łagodnym złem, ponieważ może utrudniać czytanie i utrudniać utrzymanie kodu. Niewiele trudniejsze (bo nie byłoby to łatwe rozwiązanie), ale być może czasami wciąż aktualne. Przykładem może być sprytna sztuczka bitowa, której niektóre osoby nie rozpoznają, i którą kompilator prawdopodobnie zastosuje, jeśli będzie przydatna.
Steve314,

26
Zgadzam się tutaj ze Stevem, czasem „optymalizacja” po prostu nie jest tego warta, zwłaszcza że kompilatory są tak cholernie dobre. Przykład? jeśli ijest niepodpisany, i / 2można go zastąpić i >> 1. To jest szybsze. Ale jest też bardziej tajemniczy (nie wszyscy zobaczą efekt, nawet ci, którzy to robią, mogą stracić czas). Ale najgorsze jest to, że kompilator i tak to zrobi, więc po co zaciemniać kod źródłowy;)?
Matthieu M.

19
@ Larry: Nie zrobiłem tego, więc myślę, że to dobry przykład.
Joris Meys

18
Moim zdaniem optymalizacje, nawet te proste, powinny być również uważane za złe, jeśli mają wpływ na czytelność / utrzymanie kodu i nie są oparte na rzeczywistych pomiarach wydajności.
Bart van Ingen Schenau

14
@Matthew: Naucz ich czego? Brudne i niepotrzebne sztuczki? Dlaczego? Jeśli profilowanie pokazuje, że a i/2jest rzeczywiście gorącym punktem i że (niewiarygodne, ale załóżmy) i>>1sprawia, że ​​jest szybszy, zrób to i dodaj komentarz, że to profilowanie pokazało, że jest szybsze. Jeśli rzeczywiście jest to potrzebne gdziekolwiek (co wątpię, ponieważ, jak powiedział Matthieu, kompilatory powinny być wystarczająco inteligentne, aby zrobić to sami), nowicjusze nauczą się czegoś, jeśli nie jest (co jest prawdopodobne), dlaczego chcesz podłączyć ich głowy z niepotrzebnym folklorem?
sbi

38

Kod aplikacji powinien być tylko tak dobry, jak to konieczne, ale kod biblioteki powinien być tak dobry, jak to możliwe, ponieważ nigdy nie wiesz, jak twoja biblioteka będzie używana. Więc kiedy piszesz kod biblioteki, musi on być dobry pod każdym względem, czy to pod względem wydajności, niezawodności, czy jakiejkolwiek innej kategorii.

Musisz także pomyśleć o wydajności podczas projektowania aplikacji i wybierania algorytmów . Jeśli nie jest zaprojektowany tak, aby był wydajny, żaden stopień zhakowania nie może go później sprawić, a żadna mikrooptymalizacja nie przeważy nad lepszym algorytmem.


5
Kod biblioteki powinien dokumentować, czy stara się być „tak dobry, jak to możliwe”, czy jaki jest jego cel. Kod nie musi być absolutnie optymalny, aby był użyteczny, pod warunkiem, że konsumenci używają go tylko w razie potrzeby.
supercat

1
Przykro mi, ale „bądź dobry we wszystkich aspektach” brzmi podejrzanie jak nadmierna inżynieria. Ponadto prawdopodobnie nie jest to realistyczne - w życiu zawsze chodzi o kompromisy.
śleske,

1
+1 za podkreślenie fazy projektowania; jeśli celowo rozważasz jego zalety, nie jest to przedwczesne.
Nathan Tuggy

I odwrotnie, jeśli nigdy nie wiesz, w jaki sposób twoja biblioteka będzie używana, nie wiesz, czy poświęcanie czasu na jej ulepszanie ma jakąkolwiek wartość biznesową. Więc to nie jest argument.
RemcoGerlich,

25

jaki rodzaj optymalizacji nie jest przedwczesny

Takie, które powstają w wyniku znanych problemów.


17

Kiedy optymalizacja nie jest przedwczesna, a zatem nie jest zła?

Trudno powiedzieć, co jest dobre, a co złe. Kto ma to prawo? Jeśli spojrzymy na przyrodę, wydaje się, że jesteśmy zaprogramowani na przetrwanie z szeroką definicją „przetrwania”, która obejmuje przekazywanie naszych genów potomstwu.

Powiedziałbym więc, przynajmniej zgodnie z naszymi podstawowymi funkcjami i programowaniem, że optymalizacja nie jest zła, gdy jest zgodna z celem reprodukcji. Dla facetów są blondynki, brunetki, rude głowy, wiele uroczych. W przypadku dziewcząt są faceci, a niektóre z nich wydają się być w porządku.

Być może powinniśmy optymalizować w tym celu i tam pomaga korzystanie z profilera. Narzędzie do profilowania pozwoli Ci lepiej ustalać priorytety optymalizacji i czasu, a także zapewnia szczegółowe informacje o hotspotach i ich przyczynach. To da ci więcej wolnego czasu poświęconego na rozmnażanie i jego pogoń.


3
To odświeżające, gdy ktoś przynosi świeże spojrzenie temu staremu kasztanowi. Wystarczy przeczytać cały cytat Knutha, a nie tylko jedno zdanie, co?
Robert Harvey

1
@RobertHarvey Mam tam trochę wkurzenia ze strony zwierzaka - ponieważ tak wielu zdaje się cytować tylko to jedno zdanie, a tak wiele ważnych informacji kontekstowych zostaje utraconych w procesie. Nie jestem pewien, czy to świetna odpowiedź, odkąd mam odrobinę łajdaka. :-D

14

Pełny cytat określa, kiedy nie jest przedwczesna optymalizacja:

Dobry programista nie uśpi się na skutek takiego rozumowania, rozsądnie przyjrzy się krytycznemu kodowi; ale dopiero po zidentyfikowaniu tego kodu . [moje podkreślenie]

Kod krytyczny można zidentyfikować na wiele sposobów: krytyczne struktury danych lub algorytmy (np. Intensywnie używane lub „rdzeń” projektu) mogą dawać duże optymalizacje, wiele drobnych optymalizacji jest identyfikowanych za pomocą profilerów i tak dalej.


6
Tak ... dobrze jest ogolić się o 90% w stosunku do czasu przypadkowego wywołania funkcji, ale być może miałbyś większy wpływ, patrząc na kod, w którym aplikacja faktycznie spędza 80% swojego czasu, i goląc kilka procent tam.

11

Zawsze powinieneś wybrać „wystarczająco dobre” rozwiązanie we wszystkich przypadkach na podstawie swoich doświadczeń.

Słowo „optymalizacja” odnosi się do pisania „bardziej złożonego kodu niż„ wystarczająco dobrego ”, aby przyspieszyć go”, zanim faktycznie dowie się, że jest to konieczne, a tym samym czyni kod bardziej złożonym niż to konieczne. Złożoność sprawia, że ​​wszystko jest trudne, więc to nie jest dobra rzecz.

Oznacza to, że nie powinieneś wybierać super złożonej procedury sortowania plików o pojemności 100 Gb przez przezroczyste przełączanie na dysk, gdy wystarczy sortowanie proste, ale przede wszystkim powinieneś dokonać dobrego wyboru dla sortowania prostego. Ślepo wybierając Bubble Sort lub „wybierz losowo wszystkie wpisy i sprawdź, czy są w porządku. Powtórz”. rzadko jest dobry.


3

Moja ogólna zasada: jeśli nie jesteś pewien, czy potrzebujesz optymalizacji, załóż, że nie. Ale pamiętaj o tym, gdy musisz zoptymalizować. Jest jednak kilka problemów, które możesz wiedzieć z góry. Zazwyczaj wymaga to wyboru dobrych algorytmów i struktur danych. Na przykład, jeśli chcesz sprawdzić członkostwo w kolekcji, możesz być całkiem pewien, że będziesz potrzebować pewnego rodzaju ustalonej struktury danych.


3

Z mojego doświadczenia wynika, że ​​na etapie szczegółowej implementacji odpowiedź polega na profilowaniu kodu. Ważne jest, aby wiedzieć, co musi być szybsze, a co akceptowalnie szybkie.

Ważne jest również, aby wiedzieć, gdzie dokładnie jest wąskie gardło wydajności - optymalizacja części kodu, której uruchomienie zajmuje tylko 5% całkowitego czasu, nie przyniesie żadnego pożytku.

Kroki 2 i 3 opisują przedwczesną optymalizację:

  1. Niech to zadziała
  2. Test. Nie wystarczająco szybko? Profiluj to .
  3. Korzystając z danych z kroku 2, zoptymalizuj najwolniejsze sekcje kodu.

Zapomniałeś kroku 0, który brzmi: odpowiednio zarchiwizuj aplikację, aby od samego początku oczekiwać rozsądnej wydajności.
Robert Harvey

Mówiłem tylko o szczegółowej fazie wdrażania.
Gorgi Kosev

1
Pytam krok # 3 - bardzo często najlepszą odpowiedzią jest wymyślenie innego podejścia, aby nie robić powolnego kodu.
Loren Pechtel 14.01.11

1
Wybierz odpowiednie struktury danych.
jasonk

3

To nie jest optymalizacja przy wybieraniu rzeczy, które trudno zmienić, np .: platforma sprzętowa.

Dobranie struktur danych jest dobrym przykładem - kluczowym dla spełnienia zarówno funkcjonalnych, jak i niefunkcjonalnych (wydajnościowych) wymagań. Niełatwo to zmienić, a jednak będzie napędzać wszystko inne w Twojej aplikacji. Twoje struktury danych zmieniają dostępne algorytmy itp.


3

Znam tylko jeden sposób, aby odpowiedzieć na to pytanie, a mianowicie zdobyć doświadczenie w dostrajaniu wydajności. Oznacza to - pisz programy, a po ich napisaniu znajdź w nich przyspieszenia i rób to iteracyjnie. Oto jeden przykład.

Oto błąd, który popełni większość ludzi: próbują zoptymalizować program przed jego uruchomieniem. Jeśli ukończyli kurs programowania (od profesora, który tak naprawdę nie ma praktycznego doświadczenia), będą mieli kolorowe okulary w kształcie litery „O” i pomyślą, że o to właśnie chodzi . To ten sam problem, wcześniejsza optymalizacja. **

Ktoś powiedział: Najpierw napraw to, a potem szybko. Mieli rację.

Ale teraz dla kickera: jeśli zrobiłeś to kilka razy, rozpoznajesz głupie rzeczy, które wcześniej robiłeś, które powodują problemy z prędkością, więc odruchowo ich unikasz. (Rzeczy takie jak zbyt ciężka struktura zajęć, zalewanie się powiadomieniami, mylące rozmiary wywołań funkcji z ich kosztem czasu, lista jest długa i długa ...) Instynktownie unikasz ich, ale zgadnij, jak to wygląda mniej- doświadczył: przedwczesna optymalizacja!

Więc te głupie debaty trwają i trwają :)

** Mówią też, że nie musisz się już o to martwić, ponieważ kompilatory są tak dobre, a maszyny są tak szybkie w dzisiejszych czasach. (KIWI - Kill It With Iron.) Nie ma wykładniczego przyspieszenia sprzętowego lub systemowego (wykonywanego przez bardzo inteligentnych, ciężko pracujących inżynierów), które mogłyby zrekompensować wykładnicze spowolnienie oprogramowania (wykonywane przez programistów, którzy myślą w ten sposób).


2

Gdy wymagają tego wymagania lub rynek.

Na przykład wydajność jest wymagana w większości aplikacji finansowych, ponieważ kluczowe jest małe opóźnienie. W zależności od charakteru instrumentu będącego przedmiotem obrotu optymalizacja może przejść od stosowania algorytmów nieblokujących w języku wysokiego poziomu do używania języka niskiego poziomu, a nawet ekstremum - implementowanie algorytmów dopasowywania zamówień w samym sprzęcie (na przykład przy użyciu FPGA ).

Innym przykładem mogą być niektóre typy urządzeń osadzonych. Weźmy na przykład hamulec ABS; po pierwsze jest bezpieczeństwo, kiedy uderzysz w przerwę, samochód powinien zwolnić. Ale jest też wydajność, nie chciałbyś żadnych opóźnień, gdy dojdziesz do przerwy.


0

Większość osób nazwałaby optymalizację przedwczesną, jeśli optymalizujesz coś, co nie powoduje „miękkiej awarii” (działa, ale nadal jest bezużyteczne) systemu ze względu na wydajność.

Przykłady ze świata rzeczywistego.

  • Jeśli uruchomienie mojego sortowania bąbelkowego zajmuje 20 ms, optymalizacja go do 1 ms Quicksort nie poprawi ogólnej użyteczności w żaden znaczący sposób, mimo że wzrost wydajności o 2000%.

  • Jeśli załadowanie strony zajmuje 20 sekund, a my zmniejszamy ją do 1, może to zwiększyć użyteczność witryny z 0 do prawie nieskończoności. Zasadniczo coś, co zostało zepsute, ponieważ było zbyt wolne, jest teraz przydatne.


Ważne jest, aby pamiętać, że jeśli Twój program jest wywoływany 1000 razy w trakcie programu, optymalizacja od 20 ms do 1 ms to wielka sprawa.
Beefster,

0

Jaki rodzaj optymalizacji nie jest przedwczesny?

Optymalizacja, która rozwiązuje znany problem z wydajnością aplikacji, lub optymalizacja, która pozwala aplikacji spełniać dobrze zdefiniowane kryteria akceptacji.

Po zidentyfikowaniu należy poświęcić trochę czasu na ustalenie poprawki i zmierzyć korzyści związane z wydajnością.

(tzn. nie jest - „Myślę, że ten fragment kodu wygląda na powolny, zmienię X, aby używał Y, a to będzie szybsze”).

Spotkałem wiele przedwczesnych „optymalizacji”, które ostatecznie spowolniły kod - w tym przypadku przedwcześnie rozumiem, że „nie przemyślałem”. Wydajność powinna być testowana przed optymalizacją i po niej oraz utrzymywany tylko kod, który faktycznie poprawia wydajność.


0

„Przedwczesna optymalizacja jest źródłem wszelkiego zła” to coś, co prawie wszyscy z nas słyszeli / czytali

Prawdziwe. Niestety jest to również jeden z najbardziej (złośliwie) niewłaściwie używanych cytatów programistycznych wszech czasów. Ponieważ Donald Knuth stworzył mema, warto dodać oryginalny cytat z cytatu:

Powinniśmy zapomnieć o małej wydajności, powiedzmy około 97% czasu: przedwczesna optymalizacja jest źródłem wszelkiego zła. Nie powinniśmy jednak tracić naszych szans w tak krytycznych 3%. ... Dobry programista ... mądrze będzie przyjrzeć się krytycznemu kodowi; ale dopiero po zidentyfikowaniu tego kodu. ... powszechnym doświadczeniem programistów korzystających z narzędzi pomiarowych jest to, że ich intuicyjne domysły zawodzą

Zauważ, że Knuth mówił konkretnie o szybkości wykonywania w czasie wykonywania .

.. Programiści marnują ogromne ilości czasu na myślenie lub martwienie się o szybkość niekrytycznych części swoich programów.

Napisał także ten artykuł w 1974 r., Kiedy wszelkie zasoby maszynowe, w których premia i ujemna korelacja między szybkością wykonywania a utrzymywalnością programu (większa prędkość - mniej utrzymywalna) były prawdopodobnie silniejsze niż obecnie.

OK, aby odpowiedzieć na twoje pytanie, według Donalda Knutha, optymalizacja NIE jest przedwczesna, jeśli naprawi poważne wąskie gardło wydajności, które zostało zidentyfikowane (najlepiej mierzone i wskazywane podczas profilowania).

Jak powiedziałem wcześniej, „przedwczesna optymalizacja” jest jednym z najbardziej złośliwie wykorzystywanych memów, więc odpowiedź nie będzie kompletna bez kilku przykładów rzeczy, które nie są przedwczesnymi optymalizacjami, ale czasami są odtrącane jako takie:

  • wąskie gardła, które są widoczne gołym okiem i których można uniknąć przed wprowadzeniem, takie jak liczba O (N ^ 2) w obie strony do bazy danych z dużą N, gdzie istnieje alternatywa O (1)

Ponadto nie są nawet związane z szybkością wykonywania środowiska wykonawczego:

  • przemyślany projekt z góry

  • pisanie statyczne (!)

  • itp. / wszelkie formy wysiłku umysłowego

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.