Kiedy lepiej jest zoptymalizować oprogramowanie w celu uzyskania lepszej wydajności, na początku lub na końcu rozwoju?

19

Jestem młodszym programistą i zastanawiałem się, kiedy najlepiej zoptymalizować oprogramowanie w celu uzyskania lepszej wydajności (szybkości).

Zakładając, że oprogramowanie nie jest zbyt duże i skomplikowane w zarządzaniu, czy lepiej poświęcić więcej czasu na jego optymalizację na początku, czy powinienem po prostu opracować oprogramowanie, które poprawnie wykonuje wszystkie funkcje, a następnie przystąpić do optymalizacji w celu uzyskania lepszej wydajności?

joepr
źródło
7
Eksperyment myślowy: wybierasz zinterpretowany język programowania do rozwijania interaktywnej gry i odkrywasz w połowie procesu tworzenia, że ​​wybrany język nie ma prędkości niezbędnej do spełnienia wymagań dotyczących liczby klatek na sekundę. Czy jesteś po królewsku pieprzony?
Robert Harvey
8
Kolejny eksperyment myślowy: ostrożnie optymalizujesz kod w swojej grze, który Twoim zdaniem ma kluczowe znaczenie dla wydajności, ale następnie uruchamiasz profil na kodzie i odkrywasz, że zoptymalizowany kod w rzeczywistości nie przyczynia się znacząco do ogólnej wydajności, i masz zmniejszyło przejrzystość kodu. Czy zmarnowałeś swój czas?
Robert Harvey
8
Następstwo: czy jest to decyzja, czy może ważne jest, aby niektóre decyzje dotyczące wyników były podejmowane wcześnie, a inne były odraczane?
Robert Harvey
1
Pisałam i kasowałam odpowiedź i ciągle ją wpisywałam. Nie ma tylko 1 odpowiedzi na to pytanie, ponieważ to zależy. W niektórych przypadkach rzucanie się na produkt przebija wszystkie inne względy, w innych przypadkach optymalizacja od samego początku jest trudnym wymaganiem i milion innych scenariuszy, w których albo jest optymalizacja, albo nie, optymalizacja od samego początku lub wcale nie optymalizacja i cokolwiek innego.
Pieter B
Nie ważne jak na to spojrzysz. Na początku nie ma nic do optymalizacji, ponieważ nie ma nic do porównania. Nadal potrzebujesz 2 referencji, aby coś zoptymalizować: idealna wydajność (zgodnie z wymaganiami) i prawdziwa (ta, którą dostajesz, gdy coś uruchomi się).
Laiv

Odpowiedzi:

52

Najważniejszą rzeczą powinna być zawsze i na zawsze czytelność. Jeśli jest wolny, ale czytelny, mogę to naprawić. Jeśli jest zepsuty, ale czytelny, mogę to naprawić. Jeśli jest to nieczytelne, muszę zapytać kogoś innego, co to miało zrobić.

Zadziwiające jest, jak wydajny może być Twój kod, gdy koncentrujesz się tylko na jego czytelności. Tak bardzo, że generalnie ignoruję wydajność, dopóki nie mam powodu, aby się tym przejmować. To nie powinno oznaczać, że nie dbam o szybkość. Ja robię. Właśnie odkryłem, że jest bardzo mało problemów, których rozwiązania są szybsze, gdy są trudne do odczytania.

Tylko dwie rzeczy wykluczają mnie z tego trybu:

  1. Kiedy widzę szansę na pełną poprawę O , nawet wtedy, gdy n jest na tyle duże, że ktokolwiek by się przejmował.
  2. Kiedy mam testy, które pokazują prawdziwe problemy z wydajnością. Mimo wieloletniego doświadczenia nadal ufam testom bardziej niż mojej matematyce. I jestem dobry z matematyki.

W każdym razie unikaj porażenia analizy , sprawiając, że nie powinieneś wypróbowywać rozwiązania, ponieważ może nie być najszybsze. Twój kod rzeczywiście skorzysta, jeśli wypróbujesz wiele rozwiązań, ponieważ wprowadzenie zmian zmusi cię do użycia projektu, który ułatwia zmianę. Elastyczna baza kodu może być później przyspieszona tam, gdzie naprawdę tego potrzebuje. Wybierz opcję elastyczną zamiast prędkości i możesz wybrać potrzebną prędkość.

candied_orange
źródło
Zawsze uważałem, że najważniejszą rzeczą, na której twórcy oprogramowania powinni się skupić, jest jak najszybsze umieszczenie produktu na półkach przy możliwie ładnym interfejsie, a błędy i zły projekt można naprawić później.
Pieter B
12
@PieterB: niezwykle łatwo jest spowolnić rozwój dzięki strategii typu „błędy i zły projekt można naprawić później” . Zauważ, że przez zły projekt rozumiem takie rzeczy, jak nieczytelny, zawiły kod, a także kod nadinżynieryjny.
Doc Brown,
5
@Walfrat: Myślę, że twój przykład można łatwo przyspieszyć bez poświęcania czytelności, i interpretuję tę odpowiedź nie jako „czytelny kod nie ma żadnych problemów z wydajnością”, ale raczej „problemów z wydajnością nie da się automatycznie uniknąć, tworząc kod nieczytelny ”.
Doc Brown
2
@PieterB: lub masz klienta, który chce odzyskać swoje pieniądze, ponieważ zakupiony przez nich produkt jest tak wadliwy, że nie mogą z niego skorzystać.
Doc Brown,
2
@svidgen ocenianie szybkości nieczytelnego kodu bez testów jest prawie niemożliwe. Koncentrowanie się na prędkości i ignorowanie czytelności stwarza nierozpoznawalne problemy z prędkością. Skupienie się na czytelności sprawia, że ​​problemy z prędkością są tak oczywiste, że nie musisz o tym myśleć. Zobaczysz to w momencie pisania. Nawet jeśli tego nie zrobisz, przynajmniej raz go przetestujesz, będziesz w stanie znaleźć problem. Biorąc to wszystko pod uwagę, dlaczego ktoś miałby skupiać się na szybkości zamiast czytelności? Skupienie się na szybkości i ignorowanie czytelności nie daje żadnego z nich.
candied_orange
27

Jeśli konieczny jest określony poziom wydajności (wymaganie niefunkcjonalne), powinien to być cel projektowy od samego początku. Np. Może to wpłynąć na to, które technologie mogą być odpowiednie lub na strukturę przepływu danych w programie.

Ale ogólnie rzecz biorąc, nie jest możliwa optymalizacja przed napisaniem kodu: najpierw spraw, by działał, następnie popraw go, a na koniec spraw , by był szybki .

Jednym z dużych problemów z optymalizacją przed wdrożeniem większości funkcji jest to, że zablokowałeś się w nieoptymalnych decyzjach projektowych w niewłaściwych miejscach. Często istnieje (ale niekoniecznie) kompromis między utrzymywalnością a wydajnością. Większość części twojego programu jest całkowicie nieistotna dla wydajności! Typowe programy mają tylko kilka gorących punktów, które naprawdę warto zoptymalizować. Tak więc poświęcenie możliwości utrzymania w celu uzyskania wydajności we wszystkich tych miejscach, które nie wymagają wydajności, to naprawdę zły handel.

Optymalizacja pod kątem łatwości konserwacji jest lepszym podejściem. Jeśli poświęcisz swoją spryt na łatwość konserwacji i przejrzyste projekty, na dłuższą metę łatwiej będzie ci zidentyfikować krytyczne sekcje i bezpiecznie je zoptymalizować bez uszczerbku dla ogólnego projektu.

amon
źródło
15

kiedy byłby najlepszy czas na optymalizację oprogramowania w celu uzyskania lepszej wydajności (szybkości).

Zacznij od usunięcia z umysłu koncepcji, że wydajność jest tym samym, co prędkość. Wydajność jest tym, co użytkownik uważa za wydajność .

Jeśli sprawisz, że aplikacja zareaguje dwa razy szybciej na kliknięcie myszą i przejdziesz od dziesięciu mikrosekund do pięciu mikrosekund, użytkownik nie będzie się tym przejmował. Jeśli sprawisz, że aplikacja zareaguje dwa razy szybciej na kliknięcie myszą i przejdziesz od czterech tysięcy lat do dwóch tysięcy lat, znowu, użytkownik nie będzie się tym przejmował.

Jeśli twoja aplikacja będzie dwa razy szybsza i zużyjesz całą pamięć na komputerze i ulegnie awarii, użytkownik nie będzie się przejmował, że teraz jest dwa razy szybsza.

Wydajność to nauka polegająca na skutecznych kompromisach dotyczących zużycia zasobów w celu uzyskania określonego komfortu użytkowania. Czas użytkownika jest ważnym zasobem , ale nigdy nie chodzi tylko o „szybsze”. Osiągnięcie celów w zakresie wydajności prawie zawsze wymaga kompromisów, a często poświęcają czas na miejsce lub odwrotnie.

Zakładając, że oprogramowanie nie jest wyjątkowo duże i skomplikowane w zarządzaniu

To okropne założenie.

Jeśli oprogramowanie nie jest duże i skomplikowane w zarządzaniu, prawdopodobnie nie rozwiązuje interesującego problemu, na którym dba użytkownik, i prawdopodobnie jest bardzo łatwe do optymalizacji.

czy lepiej jest poświęcić więcej czasu na jego optymalizację, czy powinienem po prostu opracować oprogramowanie, które poprawnie wykonuje wszystkie funkcje, a następnie przystąpić do optymalizacji w celu uzyskania lepszej wydajności?

Siedzisz na pustej stronie i piszesz void main() {}Czy zaczynasz optymalizować? Nie ma nic do optymalizacji! Właściwa kolejność to:

  • Spraw, by się skompilował
  • Popraw to
  • Zrób to elegancko
  • Zrób to szybko

Jeśli spróbujesz to zrobić w dowolnej innej kolejności, skończy się to błędnym kodem, który jest bałaganem, a teraz masz program, który naprawdę szybko udziela błędnych odpowiedzi i jest odporny na zmiany.

Ale brakuje tam kroku. Prawdziwe prawo zamówienia jest:

  • Współpracuj z klientami i zarządem w celu ustalenia realistycznych, mierzalnych wskaźników wydajności i celów, pamiętając, że szybkość nie jest jedyną miarą, na której zależy klientom.
  • Zaimplementuj uprząż testową, która może śledzić bieżący stan projektu względem twoich celów
  • Spraw, by się skompilował
  • Uruchom testy. Jeśli nie jesteś już w swoim celu, zdaj sobie sprawę, że wcześnie mogłeś pójść złą ścieżką. Użyj nauki . Czy wprowadziłeś zły algorytm, który można naprawić, czy coś jest zasadniczo nie tak? Jeśli jest to zasadniczo złe, zacznij od nowa. Jeśli można to naprawić, wprowadź błąd i wróć do niego później.
  • Popraw to
  • Uruchom testy ponownie ...
  • Zrób to elegancko
  • Uruchom testy ponownie ...
  • Czy jesteś zgodny ze swoim celem? Jeśli tak, idź na plażę . Jeśli nie, zrób to wystarczająco szybko .
Eric Lippert
źródło
„Wydajność jest tym, co użytkownik uważa za wydajność.” - w rzeczy samej, czasem wrażenia użytkownika są lepsze, gdy rzeczy, których spodziewamy się , wymagają czasu: webdesignerdepot.com/2017/09/when-slower-ux-is-better-ux
svidgen
może „bądź naukowy” zamiast „używaj nauki” :)
niebieski
@svidgen: Pamiętam, jak raz zmieniłem kod, aby spowolnić pasek postępu. Użytkownicy odnieśli wrażenie, że wykonano prawdziwą pracę i byli z tego zadowoleni. Obliczana funkcja była przydatna, ale wyglądało na to, że program nic nie robi, jeśli wynik jest po jednej dziesiątej sekundy.
Giorgio
2
@Giorgio: To się ze mną spotyka, ale pamiętam, kiedy pierwszy raz dostałem dysk twardy i zapisałem grę lub dokument i sądzę, że coś poszło nie tak, ponieważ operacja nie zajęła zauważalnego czasu w porównaniu do zapisywania na dyskietce. Oczywiście stan gry i dokumenty są tak duże, że wróciliśmy do oszczędzania czasu.
Eric Lippert,
3

Zasadniczo najlepiej jest optymalizować wydajność później, ale widziałem, że wiele projektów się psuje, gdy programiści zdają sobie sprawę, że skończyli z oprogramowaniem, które spowalnia, gdy dodawane jest do niego znaczne obciążenie lub dane.

Tak więc moim zdaniem najlepsze byłoby podejście pośrednie; nie kładź na to zbyt dużego nacisku, ale nie lekceważ całkowicie wydajności.

Podam przykład, który widziałem wiele razy; biorąc pod uwagę bibliotekę ORM, mamy encję użytkownika, która może mieć jedno lub więcej zamówień. Zapętlmy wszystkie zamówienia dla użytkownika i dowiedzmy się, ile użytkownik wydał w naszym sklepie - naiwne podejście:

User user = getUser();
int totalAmount;
for (Order o : user.getOrders()) {
  totalAmount += o.getTotalAmount();
} 

Widziałem, jak programiści piszą podobne rzeczy, nie myśląc o implikacjach; najpierw otrzymujemy użytkownika, który, mam nadzieję, będzie tylko jednym zapytaniem SQL w tabeli użytkowników (ale może obejmować znacznie, znacznie więcej), a następnie przeglądamy zamówienia, które mogą obejmować uzyskanie wszystkich odpowiednich danych dla wszystkich wierszy zamówienia w zamówieniu , informacje o produkcie itp. - wszystko po to, aby uzyskać jedną liczbę całkowitą dla każdego zamówienia!

Liczba zapytań SQL może Cię zaskoczyć. Oczywiście zależy to od struktury twoich bytów.

W tym przypadku poprawnym podejściem byłoby najprawdopodobniej dodanie oddzielnej funkcji w celu pobrania sumy z bazy danych za pomocą osobnego zapytania zapisanego w języku zapytań dostarczonym przez ORM, i zalecałbym zrobienie tego za pierwszym razem , a nie odkładanie tego na później na później; ponieważ jeśli to zrobisz, prawdopodobnie będziesz mieć dużo więcej problemów do załatwienia i nie wiesz, od czego zacząć.

Vetle
źródło
3

Całkowita wydajność systemu jest wynikiem złożonych interakcji wszystkich elementów systemu. To system nieliniowy. Dlatego wydajność będzie zależna nie tylko od indywidualnej wydajności komponentów, ale także od wąskich gardeł między nimi.

Oczywiście nie można testować wąskich gardeł, jeśli wszystkie elementy systemu nie są jeszcze zbudowane, więc nie można naprawdę bardzo dobrze testować wcześnie. Z drugiej strony po zbudowaniu systemu może nie być łatwo wprowadzić zmiany, które należy wprowadzić, aby uzyskać żądaną wydajność. To jest kość Catch-22 .

Aby utrudnić sprawę, profil wydajności może się drastycznie zmienić po przejściu do środowiska produkcyjnego, które często nie jest dostępne wcześnie.

Więc co robisz? Cóż, kilka rzeczy.

  1. Bądź pragmatyczny. Od samego początku możesz wybrać funkcje platformy, które są „najlepszą praktyką” w zakresie wydajności; na przykład wykorzystuj pule połączeń, transakcje asynchroniczne i unikaj stanowości, co może być śmiercią wielowątkowej aplikacji, w której różni pracownicy walczą o dostęp do współużytkowanych danych. Zwykle nie testowałbyś tych wzorów pod kątem wydajności, po prostu wiedziałeś z doświadczenia, co działa dobrze.

  2. Bądź iteracyjny. Podejmij bazowe pomiary wydajności, gdy system jest stosunkowo nowy, i od czasu do czasu ponownie testuj, aby upewnić się, że nowo wprowadzony kod nie obniżył wydajności zbyt mocno.

  3. Nie zbyt wcześnie optymalizuj. Nigdy nie wiesz, co będzie ważne, a co nie będzie miało znaczenia; superszybki algorytm parsowania ciągów może nie pomóc, jeśli twój program na przykład stale czeka na operacje we / wy.

  4. Szczególnie w aplikacjach internetowych możesz skupić się nie tyle na wydajności, co na skalowalności. Jeśli aplikacja może zostać skalowana, wydajność prawie nie ma znaczenia, ponieważ możesz dodawać węzły do ​​farmy, dopóki nie będzie wystarczająco szybka.

  5. Szczególną uwagę przywiązuje się do bazy danych. Ze względu na ograniczenia integralności transakcyjnej baza danych jest wąskim gardłem, które dominuje w każdej części systemu. Jeśli potrzebujesz wysokowydajnego systemu, upewnij się, że masz utalentowanych ludzi, którzy pracują po stronie bazy danych, przeglądają plany zapytań oraz opracowują struktury tabel i indeksów, dzięki którym wspólne operacje są tak wydajne, jak to możliwe.

Większość z tych działań nie jest na początku lub na końcu projektu, ale należy stale brać w nich udział .

John Wu
źródło
1

Jestem młodszym programistą i zastanawiałem się, kiedy najlepiej zoptymalizować oprogramowanie w celu uzyskania lepszej wydajności (szybkości).

Zrozum, że istnieją 2 bardzo różne skrajności.

Pierwszą skrajnością są rzeczy, które wpływają na dużą część projektu, takie jak podział pracy na liczbę procesów i / lub wątków oraz sposób komunikacji elementów (gniazda TCP / IP? Bezpośrednie wywołania funkcji?), Czy zaimplementować zaawansowany JIT lub interpreter „jeden kod operacji na raz”, albo czy planować struktury danych, które będą podatne na SIMD, lub… Te rzeczy mają zwykle duży wpływ na implementację i stają się zbyt trudne / kosztowne, aby później je dopasować.

Druga skrajność to mikrooptymalizacje - drobne drobne poprawki w każdym miejscu. Te rzeczy zwykle nie mają prawie żadnego wpływu na implementację (i często najlepiej jest to zrobić przez kompilator), a optymalizacje, gdy masz na to ochotę, są trywialne.

Pomiędzy tymi skrajnościami znajduje się ogromny szary obszar.

To, co tak naprawdę sprowadza się do tego, to doświadczenie / wykształcone domysły wykorzystywane do odpowiedzi na pytanie „czy korzyści uzasadniają koszty”. W przypadku optymalizacji na poziomie ekstremalnym lub zbliżonym do jednego skrajnego, jeśli często się mylicie, oznacza to wyrzucenie całej pracy i ponowne uruchomienie od zera lub awarii projektu (zbyt dużo czasu poświęconego na niepotrzebnie zbyt skomplikowany projekt). W / przeciw drugiej skrajności znacznie sensowniej jest pozostawić ją, dopóki nie będziesz w stanie udowodnić, że ma to znaczenie za pomocą pomiaru (np. Profilowania).

Niestety żyjemy w świecie, w którym zdecydowanie zbyt wiele osób uważa, że ​​optymalizacja obejmuje tylko (głównie nieistotne) rzeczy z „trywialnego” ekstremum.

Brendan
źródło
1

Najłatwiej jest napisać kod, który nie jest porformantem ani nie jest łatwy do utrzymania. Trudniej jest pisać kod porformant. Jeszcze trudniej jest napisać możliwy do utrzymania kod. I najtrudniej jest napisać kod, który jest zarówno łatwy w utrzymaniu, jak i wydajny.

Ale łatwiej jest uczynić kod wykonalnym możliwym do utrzymania, niż uczynić kod wykonalnym możliwym do utrzymania.

Teraz, oczywiście, zależy to od rodzaju tworzonego systemu, niektóre systemy będą bardzo krytyczne pod względem wydajności i będą wymagały tego od samego początku. Dla niezwykle utalentowanych ludzi, takich jak Eric Lippert, którzy odpowiedzieli powyżej, systemy te mogą być wspólne; ale dla większości z nas stanowią mniejszość systemów, które budujemy.

Biorąc jednak pod uwagę stan nowoczesnego sprzętu, w większości systemów nie trzeba od samego początku zwracać szczególnej uwagi na optymalizację, ale zwykle wystarcza uniknięcie zniszczenia wydajności . Rozumiem przez to, że nie robię po prostu głupich rzeczy, takich jak przywoływanie wszystkich rekordów tabeli, aby uzyskać liczbę, zamiast tylko zapytania select count(*) from table. Po prostu unikaj błędów i staraj się zrozumieć narzędzia, których używasz.

Następnie skoncentruj się na tym, aby Twój kod był łatwy w utrzymaniu. Rozumiem przez to:

  1. Oddzielne obawy tak ściśle, jak to tylko możliwe (na przykład nie mieszaj dostępu do danych z logiką biznesową)
  2. Jeśli to możliwe, należy odwoływać się do typów abstrakcyjnych zamiast konkretnych typów
  3. Uczyń swój kod testowalnym

Utrzymywalny kod jest znacznie łatwiejszy do optymalizacji, gdy statystyki pokazują, że jest on potrzebny.

Następnie upewnij się, że Twój kod ma wiele automatycznych testów, ma to kilka zalet. Mniej błędów oznacza więcej czasu na optymalizację w razie potrzeby . Ponadto, gdy wykonujesz optymalizację, możesz iterować i znaleźć najlepsze rozwiązanie znacznie szybciej, ponieważ błędy w swoich implementacjach są znacznie szybsze.

Zautomatyzowane skrypty wdrażania i infrastruktura skryptowa są również bardzo przydatne do dostrajania wydajności, ponieważ ponownie umożliwiają szybsze iterowanie; nie wspominając o innych jego zaletach.

Jak zawsze, są wyjątki (które będą wymagały doświadczenia, aby lepiej zidentyfikować), ale ogólnie moja rada jest następująca: najpierw naucz się swoich narzędzi i unikaj wąskich gardeł w kodowaniu. Po drugie, upewnij się, że kod jest możliwy do utrzymania. Po trzecie, zautomatyzowane testy. Po czwarte, w pełni zautomatyzowane wdrożenia. Dopiero po wykonaniu tych czynności należy się martwić optymalizacją.

TheCatWhisperer
źródło
1

Mogę być stronniczy w pracy w obszarach o krytycznym znaczeniu dla wydajności, takich jak przetwarzanie obrazu i raytracingu, ale nadal twierdzę, że optymalizuję „tak późno, jak to możliwe” . Bez względu na to, jak ważne są Twoje wymagania, po pomiarach zawsze jest o wiele więcej informacji i jasności niż z góry, co oznacza, że ​​nawet najskuteczniejsze optymalizacje są zazwyczaj stosowane później po zdobyciu takiej wiedzy.

Szczególne przypadki

Ale czasami „tak późno, jak to możliwe” jest wciąż dość cholernie wczesna w niektórych szczególnych przypadkach. Jeśli mówimy o mechanizmach renderujących offline, na przykład o strukturach danych i technikach używanych do osiągnięcia wydajności faktycznie przenikają do projektu użytkownika. Może to zabrzmieć obrzydliwie, ale pole jest tak przełomowe i tak krytyczne pod względem wydajności, że użytkownicy akceptują kontrolki użytkownika specyficzne dla technik optymalizacji mających zastosowanie do konkretnego raytracera (np. Buforowanie napromieniowania lub mapowanie fotonów), ponieważ niektóre z nich są używane godzin oczekiwania na wyrenderowanie obrazu, a inne są przyzwyczajone do wyrzucania ogromnych sum pieniędzy na wynajem lub posiadanie farmy renderującej za pomocą maszyn przeznaczonych do renderowania. Użytkownicy mogą znacznie skrócić czas i pieniądze, jeśli konkurencyjny renderer offline może zaoferować niebanalne skrócenie czasu renderowania. Jest to rodzaj obszaru, w którym 5% skrócenie czasu faktycznie podnieca użytkowników.

W takich szczególnych przypadkach nie można po prostu wybrać jednej techniki renderowania chcąc nie chcąc i mamy nadzieję ją później zoptymalizować, ponieważ cały projekt, w tym projekt użytkownika, obraca się wokół wykorzystywanych struktur danych i algorytmów. Nie zawsze możesz po prostu pójść z tym, co działało dobrze dla innych ludzi, ponieważ tutaj, jako osoba, a także twoje szczególne mocne i słabe strony, w znacznym stopniu przyczyniają się do zapewnienia konkurencyjnego rozwiązania. Sposób myślenia i wrażliwość głównego programisty Arnolda różnią się od tych pracujących nad VRay, którzy stosowali zupełnie inne podejście; niekoniecznie muszą zamieniać miejsca / techniki i wykonywać najlepszą robotę (mimo że obaj są liderami branży). Musisz w pewnym sensie eksperymentować, prototypować i testować oraz znaleźć to, co „ jest szczególnie dobry w robieniu, biorąc pod uwagę nieskończony wachlarz najnowocześniejszych technik, jeśli masz nadzieję wysłać coś konkurencyjnego, co faktycznie się sprzedaje. Tak więc w tym szczególnym przypadku problemy z wydajnością przenoszą się na pierwszy plan, być może najważniejszą kwestią jeszcze przed rozpoczęciem rozwoju.

Jednak niekoniecznie jest to naruszenie optymalizacji „tak późno, jak to możliwe” , po prostu „tak późno, jak to możliwe” jest raczej wczesne w tych ekstremalnych i osobliwych przypadkach. Dowiedzenie się, kiedy i co nie potrzebuje tak wczesnych problemów z wydajnością, jeśli w ogóle, jest prawdopodobnie głównym wyzwaniem dla dewelopera. Czego nie optymalizować może być jedną z najcenniejszych rzeczy do nauczenia się i uczenia się w karierze programisty, ponieważ nie brakuje naiwnych programistów, którzy chcą wszystko zoptymalizować (i niestety nawet niektórzy weterani, którym udało się jakoś utrzymać pracę pomimo ich kontrproduktywności).

Tak późno jak to możliwe

Być może najtrudniejszą częścią jest próba zrozumienia, co to znaczy. Wciąż się uczę i programuję od prawie trzech dekad. Ale szczególnie teraz, w trzeciej dekadzie, zaczynam zdawać sobie sprawę, że to nie takie trudne. To nie jest nauka o rakietach, jeśli bardziej skupiasz się na projektowaniu niż na implementacji. Im bardziej twoje projekty pozostawiają oddech dla odpowiednich optymalizacji później bez zmian w projekcie, tym później możesz zoptymalizować. Coraz więcej produktywności zyskałem, szukając takich projektów, które pozwalają mi oddychać.

Zaprojektuj, które oferują pokój oddechowy do późniejszej optymalizacji

Tego rodzaju projekty w rzeczywistości nie są trudne do osiągnięcia w większości przypadków, jeśli możemy zastosować „zdrowy rozsądek”. Jako osobista historia zajmuję się sztukami wizualnymi jako hobby (uważam, że w pewnym stopniu pomaga to programować artystów, którzy sami rozumieją ich potrzeby i mówią w ich języku) i spędziłem trochę czasu na początku 2000 roku, używając apletów Oekaki online jako szybki sposób na doodle i udostępnianie mojej pracy oraz kontakt z innymi artystami.

W szczególności moja ulubiona strona i aplet były usiane wadami wydajnościowymi (każdy nietrywialny rozmiar pędzla spowolniłby do indeksowania), ale miał bardzo miłą społeczność. Aby obejść problemy z wydajnością, użyłem malutkich pędzli 1 lub 2-pikselowych i po prostu zapisałem moją pracę w ten sposób:

wprowadź opis zdjęcia tutaj

W międzyczasie ciągle dawałem autorowi sugestie oprogramowania w celu poprawy wydajności, a on zauważył, że moje sugestie mają szczególnie techniczny charakter, mówiąc o optymalizacji pamięci i algorytmach i tak dalej. Więc właściwie zapytał, czy jestem programistą, a ja odpowiedziałem tak i zaprosił mnie do pracy nad kodem źródłowym.

Więc spojrzałem na kod źródłowy, uruchomiłem go, profilowałem i ku mojemu przerażeniu zaprojektował oprogramowanie wokół koncepcji „abstrakcyjnego interfejsu pikselowego”, na przykład IPixel, który stał się główną przyczyną gorących miejsc dla wszystkiego z dynamiką przydziały i wysyłka dla każdego piksela każdego obrazu. Jednak nie było praktycznego sposobu na zoptymalizowanie tego bez ponownego przemyślenia całego projektu oprogramowania, ponieważ projekt uwięził go w kącie, w którym nie ma nic poza najbardziej trywialnymi mikrooptymalizacjami, gdy nasze abstrakcje działają na poziomie ziarnistym pojedynczego abstrakcyjnego piksela i wszystko zależy od tego abstrakcyjnego piksela.

Myślę, że jest to naruszenie „zdrowego rozsądku”, ale oczywiście nie było to takie rozsądne dla dewelopera. Ale to tak, jakby nie abstrakcjonować rzeczy na tak szczegółowym poziomie, w którym miliony będą tworzyć nawet najbardziej podstawowe przypadki użycia, takie jak piksele, cząstki lub małe jednostki w gigantycznej symulacji armii. Faworyzuj IImage(możesz obsłużyć wszystkie potrzebne formaty obrazów / pikseli na tym większym zbiorczym poziomie) lub IParticleSystemdo IPixellub IParticle, a następnie możesz wprowadzić najbardziej podstawowe i szybkie do napisania i łatwe do zrozumienia implementacje za takimi interfejsami i mieć całą przestrzeń do oddychania, którą trzeba będzie później zoptymalizować bez ponownego rozważania projektu całego oprogramowania.

I taki jest cel, jaki widzę obecnie. Z wyłączeniem szczególnych przypadków, takich jak renderery offline powyżej, projektuj z wystarczającą ilością miejsca do oddychania, aby zoptymalizować jak najdłużej, z możliwie największą ilością informacji z perspektywy czasu (w tym pomiarów), i zastosuj wszelkie niezbędne optymalizacje tak późno, jak to możliwe.

Oczywiście niekoniecznie sugeruję zacząć od użycia algorytmów złożoności kwadratowej na wejściach, które łatwo osiągają niebanalny rozmiar w typowych przypadkach użytkowników końcowych. Kto to robi? Ale nawet nie sądzę, że jest to taka wielka sprawa, jeśli wdrożenie można łatwo wymienić później. To nadal nie jest poważny błąd, jeśli nie musisz ponownie rozważać żadnych projektów.

Dragon Energy
źródło
0

To zależy od tego, co ta wydajność oznacza dla twojej aplikacji. I czy możliwe jest nawet zoptymalizowanie wydajności, zanim aplikacja zakończy się funkcjonalnie.

Najczęściej nie powinieneś się tym przejmować, dopóki nie będziesz miał nic lepszego do roboty, ale może być tak, że pewien poziom wydajności ma kluczowe znaczenie dla powodzenia Twojej aplikacji. Gdyby tak było i podejrzewasz, że może to nie być łatwe, powinieneś zacząć patrzeć na wydajność ze względu na „szybkie zawodzenie”.

Ważną zasadą w każdym projekcie jest skupienie się na twardych częściach. W ten sposób, jeśli okaże się, że nie możesz tego zrobić, będziesz wiedział wcześniej i będzie czas na wypróbowanie czegoś zupełnie innego lub projekt może zostać anulowany, zanim zostanie na to zbyt wiele wydane.

Martin Maat
źródło
0

Mam zamiar zasugerować, że wydajność to coś więcej niż prędkość. Obejmuje skalę (setki do tysięcy jednoczesnych użytkowników). Na pewno nie chcesz, aby aplikacja zaczęła tankować, gdy otrzyma obciążenie produkcyjne. Wydajność obejmuje ilość zasobów (np. Pamięci) zużywanych przez aplikację.

Wydajność to także łatwość użycia. Niektórzy użytkownicy wolą, aby 1 naciśnięcie klawisza wykonało zadanie w 10 sekund, niż 2 naciśnięcia klawisza wykonały zadanie w ciągu 1 sekundy. O takie rzeczy zapytaj kierownika projektu. Nie lubię wcześniej tego robić użytkownikom. W próżni mogą powiedzieć X, ale kiedy pracują z funkcjonalnym wstępnym wydaniem, mogą powiedzieć Y.

Najlepszą indywidualną prędkością jest utrzymanie zasobu, takiego jak połączenie z bazą danych. Ale dla wagi powinieneś uzyskać połączenie tak późno, jak to możliwe i zwolnić go tak szybko, jak to możliwe. Jedna podróż do bazy danych w celu uzyskania 3 rzeczy jest szybsza niż 3 osobne wycieczki do bazy danych.

Czy podróżujesz po informacje, które nie zmieniają się podczas sesji. Jeśli tak, weź go na początku sesji i przytrzymaj, to pamięć.

Wybierając typ kolekcji, weź pod uwagę funkcjonalność, szybkość i rozmiar.

Czy na pewno musisz przechowywać przedmioty w kolekcji? Częstym problemem jest wczytywanie wszystkich linii z pliku do listy, a następnie przetwarzanie listy pojedynczo. Znacznie wydajniej jest czytać plik po jednym wierszu i pomijać listę.

Zapętlasz trzy razy, kiedy możesz zapętlić raz i zrobić trzy rzeczy.

Czy jest miejsce, w którym może być konieczne przetworzenie innego wątku z oddzwanianiem. Jeśli tak, spakuj kod z uwzględnieniem tej możliwej potrzeby, jeśli nie koliduje on z bezpośrednimi potrzebami projektowymi.

Duża wydajność to także czysty kod.

Istnieje przedwczesna optymalizacja i po prostu robi się zdrowy rozsądek, co tak naprawdę nie zajmuje więcej czasu.

W bazie danych widzę przedwczesną optymalizację. Odnormalizuje prędkość, zanim wystąpi problem z prędkością. Argument, który otrzymuję, jest taki, że jeśli później zmienimy tabelę, musimy wszystko zmienić. Często można utworzyć widok prezentujący dane w ten sposób i być może trzeba będzie później zamienić go na zdenormalizowaną tabelę.

paparazzo
źródło