Kiedy powinienem dbać o wydajność?

16

Od dłuższego czasu w miejscach takich jak kanał IRC Java , SO i innych miejscach powiedziano mi coś w stylu „Martw się o wygląd kodu i jego czytelność / zrozumiałość teraz, a wydajność później, jeśli to absolutnie konieczne”. Tak więc przez długi czas tak naprawdę nie byłem OCD na temat wydajności moich małych aplikacji komputerowych lub internetowych, po prostu usuwając oczywiście nieefektywną.

Większość odpowiedzi brzmi „Co ze skalowalnością?”. To słuszny punkt, ale jeśli moja aplikacja została zbudowana tylko do analizowania, powiedzmy, plików o długości 10 000 wierszy, czy powinienem sprawić, że mój kod będzie bałaganem dla małego odsetka osób, które będą zapisywać pliki w liczbie 1 000 000 wierszy?

Moje główne pytanie brzmi: kiedy powinienem wymienić łatwe, ale nieco nieefektywne sposoby wykonywania zadań dla wielkich, gigantycznych, skomplikowanych bestii, które robią rzeczy niezwykle szybko, ale niszczą wszelkie możliwe sposoby aktualizacji i sprawiają, że kod jest nadmiernie trudny i podatny na przepisywanie przez innego programistę?

TheLQ
źródło

Odpowiedzi:

23

Martw się o wydajność, gdy staje się problemem.

Jeśli napiszesz małą aplikację do przetwarzania 10 000 plików linii i otrzymasz 1 000 000 plików linii co 100 plik, prawdopodobnie nie ma znaczenia, że ​​przetworzenie tego jednego pliku trwa dłużej. Jeśli jednak regularnie otrzymujesz pliki, które są 5–10 razy większe niż początkowo, a aplikacja zajmuje zbyt wiele czasu, możesz rozpocząć profilowanie i optymalizację.

Teraz powiedziałem „zbyt długo, aby wykonać swoją pracę”. Decyzja należy do użytkownika lub organizacji sponsorującej. Jeśli wykonuję zadanie i zajmuje mi to 5 minut, aby zrobić coś, gdy zajęło mi to 3 bez oprogramowania lub innego narzędzia, prawdopodobnie zgłosiłbym raport o błędzie lub prośbę o konserwację, aby to poprawić.

Jeśli jesteś użytkownikiem, to jak długo oprogramowanie zajmie wykonanie swojej pracy, zależy tylko od Ciebie - tylko Ty możesz zdecydować, czy chcesz to zrobić szybciej, czy też chcesz dłużej czekać na bardziej czytelny kod.

Thomas Owens
źródło
Zaczynam profilować i optymalizować Jeśli 1) zadanie trwa
zbyt
10

Moje główne pytanie brzmi: kiedy powinienem wymienić łatwe, ale nieco nieefektywne sposoby wykonywania zadań dla wielkich, gigantycznych, skomplikowanych bestii, które robią rzeczy niezwykle szybko, ale niszczą wszelkie możliwe sposoby aktualizacji i sprawiają, że kod jest nadmiernie trudny i podatny na przepisywanie przez innego programistę?

Jest to zwykle fałszywa dychotomia . Możesz pisać cudownie wydajny, czytelny i łatwy do utrzymania kod. Możesz pisać cudownie nieefektywne, niemożliwe do utrzymania sterty bałaganu.

Kiedy mam do czynienia z problemami z wydajnością, zwykle staram się myśleć o problemach biznesowych, które rozwiązuję. Jak zachowa się moje oprogramowanie, gdy będą go używać moi klienci. Czy wydajność moich aplikacji uszczęśliwi Jacoba Nielsena ?

Sam Saffron
źródło
5
++ FALSE DICHOTOMY! Czy nigdy się nie nauczą? Kiedy znajdziesz i naprawisz problem z wydajnością, kod jest nie tylko szybszy, ale i lepszy . Żałuję tylko, że mam tylko jeden głos, by dać!
Mike Dunlavey,
+1 za napisanie, że ZWYKLE jest to fałszywa dychotomia ... nie zawsze, ale zwykle.
Dan Rosenstark
1
-1 do pisania jest zwykle fałszywą dychotomią - jest to zwykle poprawna, a tylko w rzadkich przypadkach fałszywa dychotomia. Przez ponad 30 lat mojej kariery programistycznej widziałem zbyt wiele „dobrze zaplanowanych” optymalizacji wydajności, które w rzeczywistości utrudniały zrozumienie i utrzymanie kodu (i często optymalizowały coś, co było całkowicie niepotrzebne do optymalizacji).
Doc Brown
5

Truizm, który nauczyłem się studiować mikroprocesory na studiach, które mi pozostały: „Spraw, by wspólny przypadek był szybki. Spraw, by rzadka sprawa była poprawna”.

Jeśli tylko niewielki procent użytkowników dusi kod przy wprowadzaniu dwóch rzędów wielkości większych niż to, co miał obsługiwać, nie przejmuj się. Upewnij się, że odpowiednio obsługuje dane wejściowe, jeśli dają wystarczająco dużo czasu i nie pozostawiają niczego zepsutego w bezużyteczności, jeśli zabiją zadanie przed jego zakończeniem.

Ale kiedy coraz więcej osób zaczyna z niego korzystać w ten sposób (lub zaczyna mówić: „Wiesz, bardzo chciałbym użyć tego narzędzia, które napisałeś w moich cotygodniowych raportach TPS, ale zajmuje to cały cholerny dzień”), to wtedy zaczynasz rozważać zamianę łatwości konserwacji w celu zwiększenia wydajności.

BlairHippo
źródło
1

Moje główne pytanie brzmi: kiedy powinienem wymienić łatwe, ale nieco nieefektywne sposoby wykonywania zadań dla wielkich, gigantycznych, skomplikowanych bestii, które robią rzeczy niezwykle szybko, ale niszczą wszelkie możliwe sposoby aktualizacji i sprawiają, że kod jest nadmiernie trudny i podatny na przepisywanie przez innego programistę?

„Martwienie się o wygląd kodu i jego czytelność / zrozumiałość teraz, a wydajność później, jeśli jest to absolutnie konieczne”, jest łatwym rozwiązaniem i ogólnie nie jest pomocne. dobry projekt będzie łatwy w utrzymaniu, łatwy do odczytania i wydajny.

wydajność jest jednym z powszechnych elementów dobrego projektu. jeśli twój program jest powolny i marnotrawny, tak naprawdę nie można go ponownie użyć. kiedy musisz naprawić ten bałagan, wymuszasz aktualizacje na swoich klientach, chyba że jest to zbyt długi czas na ich aktualizację. ten wolny program staje się wielkim bałaganem, który jest zbyt kosztowny, aby go poprawić. wtedy wybierają alternatywę, ponieważ nie odpowiada ona ich potrzebom. diagnozowanie, aktualizowanie i radzenie sobie ze skutkami ubocznymi ulepszeń złego projektu często przewyższa początkowy czas opracowywania go, aby był wydajny, działał poprawnie i miał genrycznie dobry projekt. ten program nadaje się do wielokrotnego użytku i wymaga niskiej konserwacji (wygrana).

dlatego krótka odpowiedź na twoje pytanie brzmi: „nie marnuj. pisz do ponownego użycia. możesz być leniwy przy prototypowaniu / opracowywaniu próbnych koncepcji, ale nie używaj tego prototypu do kodu produkcyjnego”.

pamiętaj o marnotrawstwie projektów i unikaj ich podczas pisania programów produkcyjnych i programów, które zamierzasz ponownie wykorzystać. podczas implementacji jest idealny czas, aby napisać swój program, aby nie marnować - masz jasne pojęcie o szczegółach i jego działaniu, a naprawę po jego napisaniu jest bardzo bolesne i nieskuteczne. wiele osób uważa, że ​​małe profilowanie (być może) na końcu lub jeśli występuje problem, jest wystarczające, gdy zwykle zbyt długo zajmuje przeprojektowanie / zmiana, a nieefektywność jest tak duża i tak powszechna, że ​​nie rozumiesz programu dobrze na podstawie wyników profilu. takie podejście zajmuje niewiele czasu podczas implementacji i (zakładając, że zrobiłeś to wystarczająco dużo razy) zazwyczaj powoduje, że projekt jest kilka razy szybszy i można go użyć w wielu innych kontekstach. nie marnować się, wybór dobrych algorytmów, przemyślenie implementacji i ponowne użycie właściwych implementacji to elementy dobrego projektu; z których każdapoprawia czytelność, łatwość konserwacji i ponowne użycie częściej niż boli.

justin
źródło
0

Staram się, aby kod był czytelny - wydajność niech będzie przeklęta.

Kiedy i jeśli kod okaże się zbyt wolny, zmienię go tak, aby był szybszy. Zazwyczaj proces refaktoryzacji następuje z dużą ilością komentarzy, ponieważ kod jest zwykle mniej czytelny.

Josip Medved
źródło
0

Um - nigdy?

Poważnie, kod powinien być zawsze napisany, aby był łatwy do zrozumienia i obsługi.

Jeśli chodzi o to, kiedy radzić sobie z problemami z wydajnością, radzimy sobie z nimi po ich zidentyfikowaniu, nie optymalizuj wstępnie kodu, ponieważ wtedy będziesz tylko zgadywał, gdzie są problemy z wydajnością.

Jeśli Twój kod jest napisany tak, aby był przejrzysty, zwięzły, zrozumiały i łatwy w utrzymaniu, to Ty lub inny programista nie powinien mieć problemu z refaktoryzacją kodu w celu zwiększenia jego wydajności.

Noah Goodrich
źródło
3
Nie zgadzam się z tym. Wymaganie dotyczące wydajności jest ważnym niefunkcjonalnym wymaganiem dla systemu.
Thomas Owens
Technicznie, jeśli istnieje jasno określony wymóg związany z wydajnością, można powiedzieć, że zidentyfikowałeś problem z wydajnością i musisz go uwzględnić w swoim rozwiązaniu. To, o czym mówię, jest sprytne, abyś mógł uniknąć niespecyficznych „potencjalnych” problemów.
Noah Goodrich,
Ach Tak, masz absolutną rację w tym przypadku. Nie martw się o możliwości, ponieważ jest ich tak wiele, ale skup się na tym, co wiesz.
Thomas Owens
0

Zwykle piszę kod, aby był czytelny przede wszystkim. Jeśli i tylko jeśli okaże się, że program działa zbyt wolno, aby wykonać swoją pracę, profiluję i optymalizuję. To powiedziawszy, nie ma nic złego w nawykach wykonywania typowych optymalizacji, które nie wpływają na czytelność twojego kodu. Oznacza to, że jeśli fragment kodu można napisać na dwa jednakowo (lub prawie jednakowo) czytelne sposoby, wybierz ten, który jest zwykle szybszy.

Na przykład w Pythonie wyrażenia listy (lub wyrażenia generatora) są zwykle szybsze niż równoważna forpętla, więc używam wyrażeń listy, gdzie mogę, jeśli nie wpływają na czytelność (na przykład nie zagnieżdżam wyrażeń listy, jeśli Mogę tego uniknąć i zamiast tego użyć pętli for, ponieważ interpretacja listy zagnieżdżonej może być trudna do mentalnego przeanalizowania).

Podobnie niezmienne typy danych są zwykle szybsze niż zmienne, dlatego używam niezmiennych typów danych tam, gdzie mogę.

Chinmay Kanchi
źródło
0

Jeśli pracujesz w obszarach o krytycznym znaczeniu dla wydajności, nie możesz odkładać wydajności na później. Jest to jedna z najważniejszych rzeczy, o których należy pomyśleć przy wczesnym projektowaniu w takich przypadkach oraz w sposób związany z utrzymywalnością efektu końcowego.

Nie można zaprojektować i wdrożyć serwera na dużą skalę, a po prostu zacząć pisać łatwy, dobrze udokumentowany kod, który po prostu używa funkcji blokowania do wszystkiego z globalną blokadą wątków, która blokuje cały system, aby przetworzyć każde indywidualne żądanie klienta, nie wprowadzając żadnego w ogóle myślał o stanie wspólnym, rywalizacji wątków i asynchroniczności. Taki jest przepis na katastrofę i potrzebę przeprojektowania i przepisania dużej części dobrze udokumentowanego kodu, który napisałeś w sposób, który może prowadzić do najtrudniejszej do utrzymania bazy kodu, jaką można sobie wyobrazić, nękanej warunkami wyścigowymi i impasami w wyniku prób aby osiągnąć wymaganą wydajność z perspektywy czasu, zamiast myśleć z góry o wydajnych, prostych i działających projektach.

Zespół twórców gier trwający 8 miesięcy od produkcji z silnikiem, który uruchamia jedynie 2 klatki na sekundę na swoim najpotężniejszym sprzęcie z 32 rdzeniami, a jednocześnie ma tendencję do zatrzymywania się na 15 sekund za każdym razem, gdy ekran jest zajęty, nie jest w stanie natychmiast uzyskać użytecznego produktu po prostu naprawienie jednego małego zlokalizowanego punktu aktywnego. Są szanse, że ich projekt jest FUBAR w sposób, który uzasadnia epicką rewizję tablicy kreślarskiej i zmiany w projekcie, które mogą kaskadować w każdym rogu bazy kodu.

Z Johnem Carmackiem opowiadał kiedyś o tym, jak demo techniczne musi działać przy minimum setkach do tysięcy klatek na sekundę, aby włączyć go do produkcji. To nie jest niezdrowa obsesja na punkcie wydajności. Wie z góry, że gry muszą działać w całości przy 30+ FPS, aby klienci uznali, że jest to akceptowalne. W rezultacie jeden mały aspekt, taki jak system miękkich cieni, nie może działać przy 30 FPS, w przeciwnym razie gra jako całość nie może być wystarczająco szybka, aby zapewnić wymagane informacje zwrotne w czasie rzeczywistym. Jest bezużyteczny, dopóki nie osiągnie wymaganej wydajności. W obszarach krytycznych pod względem wydajności, w których istnieje podstawowy warunek wydajności, rozwiązanie, które nie osiąga odpowiedniej prędkości, nie jest w rzeczywistości lepsze niż takie, które w ogóle nie działa,. I nie można zaprojektować wydajnego systemu miękkich cieni, który działa z prędkością setek do tysięcy klatek na sekundę, jak jest to wymagane w przypadku silnika gry w czasie rzeczywistym, chyba że z góry zastanowisz się nad jego wydajnością. W rzeczywistości w takich przypadkach ponad 90% pracy jest zorientowane na wydajność, ponieważ wymyślenie miękkiego systemu cieni, który działa dobrze przy 2 godzinach na klatkę przy użyciu śledzenia ścieżki, jest banalne, ale nie można oczekiwać, że dostroi się do pracy z setkami klatek na sekundę bez zupełnie innej zmiany podejścia.

Gdy wydajność jest podstawową częścią projektu aplikacji, nie można oczekiwać, że osiągnie się wydajność z perspektywy czasu, nie tracąc radykalnie więcej czasu niż zaoszczędzono, ignorując go, ponieważ nie można oczekiwać, że osiągnie się działający projekt z perspektywy czasu. Nikt nie mówi: „ Nie ma sensu odkładać na później myślenia o projektowaniu. Po prostu dobrze udokumentuj swój kod, a później możesz wymyślić odpowiedni projekt ”. Ale w architekturach krytycznych pod względem wydajności to właśnie robisz, jeśli nie przykładasz zbyt wiele uwagi i nie zastanawiasz się nad wydajnym projektowaniem z góry.

To nie znaczy, że musisz od razu dostroić swoje implementacje. Aby uzyskać szczegółowe informacje na temat implementacji, po pomiarze jest dużo miejsca na iterację w kierunku szybszych rozwiązań, pod warunkiem, że projekt nie będzie musiał się zmieniać, a często jest to najbardziej produktywny sposób. Ale na poziomie projektowania oznacza to, że od samego początku trzeba dokładnie przemyśleć, w jaki sposób projekt i architektura będą odnosić się do wydajności.

Kluczową różnicą jest tutaj design. Z perspektywy czasu nie jest łatwo wprowadzać duże zmiany w projektach, ponieważ projekty gromadzą zależności, a zależności ulegną zerwaniu w przypadku zmiany projektu. A jeśli projekt wymaga racjonalnej wydajności lub, w niektórych przypadkach, że jego jakość jest w dużej mierze mierzona przez jego efektywność, nie należy oczekiwać, że uda się osiągnąć właściwy projekt jako uzupełnienie. W przypadku produktów konkurencyjnych, w których wydajność jest ogromnym aspektem jakości, niezależnie od tego, czy chodzi o systemy operacyjne, kompilatory, procesory wideo, raytracery, silniki gier czy silniki fizyki, od samego początku starannie rozważano przemyślenia na temat wydajności i reprezentacji danych. W takich przypadkach optymalizacja nie jest zbyt przedwczesna. Umieszczał taką myśl dokładnie w najbardziej produktywnym czasie, aby to zrobić,


źródło