Czy programista powinien najpierw dążyć do czytelności lub wydajności? [Zamknięte]

82

Często programista staje przed wyborem między dwoma możliwymi sposobami rozwiązania problemu - jednym idiomatycznym i czytelnym, a drugim mniej intuicyjnym, ale wydajniejszym. Na przykład w językach opartych na C istnieją dwa sposoby mnożenia liczby przez 2:

int SimpleMultiplyBy2(int x)
{
    return x * 2; 
}

i

int FastMultiplyBy2(int x)
{
    return x << 1;
}

Pierwsza wersja jest prostsza do wyboru zarówno dla czytelników technicznych, jak i nietechnicznych, ale druga może działać lepiej, ponieważ przesuwanie bitów jest operacją prostszą niż mnożenie. (Na razie załóżmy, że optymalizator kompilatora nie wykryłby tego i nie zoptymalizowałby tego, chociaż jest to również brane pod uwagę).

Jako programista, co byłoby lepsze jako pierwsza próba?

JohnMcG
źródło
Nieco szorstkie. Dobre pytanie o obawy, które czasami wszyscy mamy. +1
Inisheer
3
Ten przykład jest oczywiście wymyślony i trywialny. Tak naprawdę nie miałbyś funkcji z mnożnikiem zakodowanym na stałe.
JohnMcG
1
Chodzi o to, że widzę wiele pytań typu „czy <działa lepiej niż <=?” To jest złe pytanie - właściwe (pierwsze) pytanie brzmi: idiomatyczne lub konwencjonalne, a następnie martw się o wydajność.
JohnMcG
1
To jedno z najlepszych pytań, które przeczytałem na temat stackoverflow. Dochodzi do sedna działania komputerów, a nie tylko do semantyki języka. +1
WolfmanDragon
2
@OutlawLemur Jestem tego świadomy. Ale niektórzy pytają, czy nie byłoby lepiej, na przykład, skonstruować pętle przy użyciu <lub <= (przy czym wartość porównawcza jest wcześniej zwiększana w tym drugim przypadku).
JohnMcG

Odpowiedzi:

109

Przegapiłeś jednego.

Najpierw kod pod kątem poprawności, potem dla jasności (oczywiście oba są często połączone!). Wreszcie, i tylko wtedy, gdy masz prawdziwe dowody empiryczne, których naprawdę potrzebujesz, możesz przyjrzeć się optymalizacji. Przedwczesna optymalizacja jest naprawdę zła. Optymalizacja prawie zawsze kosztuje czas, przejrzystość i łatwość konserwacji. Lepiej upewnij się, że kupujesz coś wartościowego.

Zwróć uwagę, że dobre algorytmy prawie zawsze pokonują lokalne dostrajanie. Nie ma powodu, dla którego nie możesz mieć kodu, który jest poprawny, jasny i szybki. Będziesz miał jednak nieuzasadnione szczęście, jeśli zaczniesz skupiać się na `` szybkim ''.

simon
źródło
To zdecydowanie najlepsza odpowiedź. Popraw algorytm, a nie kod. Dzięki subtelnym zmianom mogę sprawić, że jscript Sieve of Erastosthenes przewyższy identyczną wersję C ++. (Nie Sieve of Atkins, moja własna metoda).
Peter Wone
2
Szkoda, że ​​nie możesz ulubionych odpowiedzi. :)
Sandor Davidhazi
59

Najpierw IMO oczywistą czytelną wersję, dopóki nie zostanie zmierzona wydajność i wymagana jest szybsza wersja.

Kenny
źródło
Zgadzam się. W zeszłym roku zaimplementowałem główny komponent jako bazę kodu Java po stronie serwera mojej firmy i dołożyłem wszelkich starań, aby był czytelny. Później okazało się, że wystąpiły problemy z wydajnością i dokonano poważnych zmian w jego projekcie, co doprowadziło do czegoś, co jest nieco mniej czytelne.
Ryan Delucchi
46

Weź to od Don Knuth

Przedwczesna optymalizacja jest źródłem wszelkiego zła (a przynajmniej większości) w programowaniu.

Ryan
źródło
Cytat nie pochodzi od samego Dona, ale od Hoare'a. Don po prostu sprawił, że stał się popularny. Sprawdź wikipedię.
kohlerm
1
I jest to selektywne cytowanie jednej klauzuli z całego akapitu, która zawiera kilka bardzo ważnych zastrzeżeń .
user207421
19

Czytelność 100%

Jeśli Twój kompilator nie może wykonać optymalizacji "x * 2" => "x << 1" za Ciebie - zdobądź nowy kompilator!

Pamiętaj również, że 99,9% czasu programu spędza na oczekiwaniu na dane wejściowe użytkownika, oczekiwaniu na zapytania do bazy danych i oczekiwaniu na odpowiedzi sieci. O ile nie wykonasz wielokrotnych 20 bajlionów razy, nie będzie to zauważalne.

James Curran
źródło
8

W podanym przykładzie 99,9999% kompilatorów wygeneruje ten sam kod w obu przypadkach. Co ilustruje moją ogólną zasadę - pisz najpierw pod kątem czytelności i łatwości konserwacji, a optymalizuj tylko wtedy, gdy zajdzie taka potrzeba.

Paul Tomblin
źródło
Kompilatory języka C skompilują się do innego kodu asemblera dla dwóch pokazanych przykładów. Pierwsza tworzy pętlę, podczas gdy druga tworzy instrukcję shift left. Powinno to dotyczyć wszystkich kompilatorów w stylu C, ponieważ nie testowałem każdego z nich, nie mogę nic obiecać.
WolfmanDragon
Z pewnością w tym konkretnym przykładzie. Jest wiele przypadków, w których tak nie jest, więc ogólne pytanie jest nadal dobre
Mark Baker
@WolfmanDragon, o czym ty do cholery mówisz? Dlaczego „* 2” miałby generować pętlę? Kiedy próbuję to z "gcc -O2 -s", otrzymuję instrukcje addl w obu przypadkach.
Paul Tomblin
1
Jeśli twój kompilator tworzy pętlę w tej funkcji, polecam ci inny kompilator!
Martin Vilcans
8

Czytelność na pewno. Nie martw się o prędkość, chyba że ktoś narzeknie

Miles
źródło
8

Czytelność.

Kodowanie wydajności ma swój własny zestaw wyzwań. Joseph M. Newcomer powiedział to dobrze

Optymalizacja ma znaczenie tylko wtedy, gdy ma znaczenie. Kiedy to ma znaczenie, jest ważne, ale dopóki nie wiesz, że to ważne, nie trać na to dużo czasu. Nawet jeśli wiesz, że to ma znaczenie, musisz wiedzieć, gdzie to ma znaczenie. Bez danych dotyczących wydajności nie będziesz wiedział, co zoptymalizować, i prawdopodobnie zoptymalizujesz niewłaściwą rzecz.

Rezultat będzie niejasny, trudny do napisania, trudny do debugowania i trudny w utrzymaniu kodu, który nie rozwiąże problemu. W związku z tym ma podwójną wadę: (a) wzrost kosztów tworzenia oprogramowania i utrzymania oprogramowania oraz (b) brak wpływu na wydajność.

nwahmaet
źródło
5

Czytelność. Czas na optymalizację jest wtedy, gdy przechodzisz do testów beta. W przeciwnym razie nigdy nie wiesz, na co musisz poświęcić czas.

Nie ja
źródło
5

Najpierw postawiłbym na czytelność . Biorąc pod uwagę fakt, że przy zoptymalizowanych językach i ogromnie załadowanych maszynach, które mamy w dzisiejszych czasach, większość kodu, który piszemy w czytelny sposób, będzie działać przyzwoicie.

W niektórych bardzo rzadkich scenariuszach, w których jesteś prawie pewien, że będziesz miał pewną wydajność (może to wynikać z niektórych złych doświadczeń z przeszłości), i udało ci się znaleźć dziwną sztuczkę, która może dać ci ogromną przewagę wydajności, możesz wybrać że. Ale powinieneś bardzo dobrze skomentować ten fragment kodu, co pomoże uczynić go bardziej czytelnym.

Vijesh VP
źródło
4

Często pomijanym czynnikiem w tej debacie jest dodatkowy czas potrzebny programiście na nawigację, zrozumienie i modyfikację mniej czytelnego kodu. Biorąc pod uwagę, że czas programisty kosztuje sto dolarów za godzinę lub więcej, jest to bardzo realny koszt.
Każdy wzrost wydajności jest równoważony przez ten bezpośredni dodatkowy koszt rozwoju.

Rik
źródło
4

Umieszczenie tam komentarza z wyjaśnieniem uczyniłoby go czytelnym i szybkim.

To naprawdę zależy od rodzaju projektu i tego, jak ważna jest wydajność. Jeśli tworzysz grę 3D, zwykle jest wiele typowych optymalizacji, które będziesz chciał wrzucić po drodze i nie ma powodu, aby tego nie robić (po prostu nie daj się zbyt wcześnie ponieść emocjom). Ale jeśli robisz coś podstępnego, skomentuj to, aby każdy, kto na to spojrzy, wiedział, jak i dlaczego jesteś podstępny.

Gerald
źródło
3

Odpowiedź zależy od kontekstu. Na przykład w programowaniu sterowników urządzeń lub tworzeniu gier druga forma jest akceptowalnym idiomem. W aplikacjach biznesowych nie tak bardzo.

Najlepiej jest rozejrzeć się po kodzie (lub w podobnych, udanych aplikacjach), aby sprawdzić, jak robią to inni programiści.

ilitirit
źródło
3

użycie << spowodowałoby mikro optymalizację. Zasada Hoare'a (nie Knutsa):

Przedwczesna optymalizacja jest źródłem wszelkiego zła.

ma zastosowanie i powinieneś przede wszystkim używać bardziej czytelnej wersji.

Jest to reguła, która jest często nadużywana przez IMHO jako wymówkę do projektowania oprogramowania, które nigdy nie może się skalować lub działać dobrze.

kalarepa
źródło
3

Obie. Twój kod powinien równoważyć oba; czytelność i wydajność. Ponieważ ignorowanie któregokolwiek z nich zepsuje zwrot z inwestycji w projekt, który ostatecznie jest wszystkim, co ma znaczenie dla twojego szefa.

Zła czytelność skutkuje zmniejszoną konserwowalnością, co skutkuje większymi nakładami na konserwację, co skutkuje niższym zwrotem z inwestycji.

Zła wydajność skutkuje zmniejszeniem inwestycji i bazy klientów, co skutkuje niższym zwrotem z inwestycji.

Kon
źródło
2

Im większa baza kodu, tym większa czytelność ma kluczowe znaczenie. Próba zrozumienia jakiejś małej funkcji nie jest taka zła. (Zwłaszcza, że ​​nazwa metody w tym przykładzie daje wskazówkę.) Nie jest tak dobry dla jakiegoś epickiego fragmentu kodu ubera napisanego przez samotnego geniusza, który właśnie rzucił kodowanie, ponieważ w końcu dostrzegł szczyt swojej złożoności i właśnie to napisał dla ciebie i nigdy, przenigdy tego nie zrozumiesz.

mspmsp
źródło
2

Jeśli martwisz się o czytelność swojego kodu, nie wahaj się dodać komentarza, aby przypomnieć sobie, co i dlaczego to robisz.

Michael McCarty
źródło
2

Zawsze powinieneś maksymalnie optymalizować, zawsze liczy się wydajność. Powodem, dla którego mamy dziś bloatware, jest to, że większość programistów nie chce zajmować się optymalizacją.

Powiedziawszy to, zawsze możesz umieścić komentarze tam, gdzie sprytne kodowanie wymaga wyjaśnienia.

Lance Roberts
źródło
Zgadzam się na pewnym poziomie. Uważam, że nie należy wprowadzać mikrooptymalizacji, jak podano w pierwotnym pytaniu. Musisz zaprojektować swój system w taki sposób, aby optymalnie wykorzystywać zasoby. W tej dziedzinie można uzyskać znacznie więcej wydajności.
Erik van Brakel
Mamy dziś nadużywanie, ale nie winię za to braku optymalizacji. Winię za to przesadny projekt, walenie w muchy bazookami, budowanie liniowców oceanicznych, gdy potrzebne są tylko łodzie wiosłowe. Wtedy oczywiście jest to ciężkie.
Mike Dunlavey
Zgodziłbym się z Wami obojgiem, że optymalizacja projektu jest najważniejsza. Powiedziałbym również, że to samo podejście należy zastosować na wszystkich poziomach procesu inżynierii oprogramowania. Jeśli nie zawracasz sobie głowy optymalizacją na poziomie kodu, prawdopodobnie brakuje ci również podczas projektowania.
Lance Roberts,
2

Nie pracuję w Google, więc wybrałem złą opcję. (optymalizacja)

W rozdziale 6 książki Jona Bentleya „Perły programowania” opisuje, w jaki sposób jeden system przyspieszył 400 razy dzięki optymalizacji na 6 różnych poziomach projektowania. Uważam, że nie dbając o wydajność na tych 6 poziomach projektowania, współcześni wykonawcy mogą łatwo osiągnąć 2-3 rzędy wielkości spowolnienia w swoich programach.

papierowy koń
źródło
1

Bitshift wobec mnożenia jest trywialne optymalizacji że zyski obok niczego . Jak już zostało powiedziane, Twój kompilator powinien to zrobić za Ciebie. Poza tym wzmocnienie jest w każdym razie pomijalne, podobnie jak procesor, na którym działa ta instrukcja.

Z drugiej strony, jeśli musisz wykonać poważne obliczenia, będziesz potrzebować odpowiednich struktur danych. Ale jeśli twój problem jest złożony, poznanie tego jest częścią rozwiązania. Na przykład rozważ wyszukanie numeru identyfikacyjnego w tablicy 1000000 nieposortowanych obiektów. Następnie rozważ ponownie użycie drzewa binarnego lub mapy skrótów.

Ale optymalizacje takie jak n << C są zwykle pomijalne i trywialne do zmiany w dowolnym momencie. Uczynienie kodu czytelnym nie jest.

mstrobl
źródło
1

To zależy od zadania, które należy rozwiązać. Zwykle czytelność jest ważniejsza, ale nadal istnieją pewne zadania, w których należy pomyśleć o wydajności. I nie możesz po prostu spędzić jednego dnia na profilowaniu i optymalizacji, gdy wszystko działa idealnie, ponieważ sama optymalizacja może wymagać przepisania wystarczającej części kodu od zera. Ale w dzisiejszych czasach nie jest to powszechne.

akalenuk
źródło
1

Nie ma sensu optymalizować, jeśli nie znasz swoich wąskich gardeł. Być może sprawiłeś, że funkcja była niewiarygodnie wydajna (zwykle kosztem do pewnego stopnia czytelności) tylko po to, aby stwierdzić, że ta część kodu prawie nigdy nie działa lub spędza więcej czasu na uderzaniu w dysk lub bazę danych, niż kiedykolwiek zaoszczędzisz na kręceniu bitów. Nie możesz więc mikro-optymalizacji, dopóki nie będziesz mieć czegoś do zmierzenia, a wtedy równie dobrze możesz zacząć od czytelności. Jednak podczas projektowania całej architektury należy pamiętać zarówno o szybkości, jak i zrozumiałości, ponieważ obie mogą mieć ogromny wpływ i być trudne do zmiany (w zależności od stylu kodowania i metedologii).

ICR
źródło
1

Szacuje się, że około 70% kosztów oprogramowania jest w utrzymaniu. Czytelność sprawia, że ​​system jest łatwiejszy w utrzymaniu, a tym samym obniża koszty oprogramowania przez cały okres jego użytkowania.

Są przypadki, w których wydajność jest ważniejsza od czytelności, ale są one nieliczne.

Zanim poświęcę czytelność, pomyśl „Czy ja (lub Twoja firma) jestem przygotowany, aby poradzić sobie z dodatkowymi kosztami, które w ten sposób dodam do systemu?”

Peter Tomlins
źródło
1

Jak prawie wszyscy powiedzieli w swoich odpowiedziach, wolę czytelność . 99 ze 100 projektów, które prowadzę, nie ma sztywnych wymagań dotyczących czasu reakcji, więc jest to łatwy wybór.

Zanim zaczniesz programować, powinieneś już znać odpowiedź. Niektóre projekty mają określone wymagania dotyczące wydajności, takie jak „potrzeba być w stanie uruchomić zadanie X w Y (mili) sekundach”. Jeśli tak jest, masz cel, do którego dążysz, i wiesz, kiedy musisz go zoptymalizować, a kiedy nie. (miejmy nadzieję) jest to określane na etapie wymagań projektu, a nie podczas pisania kodu.

Dobra czytelność i możliwość późniejszej optymalizacji są wynikiem odpowiedniego zaprojektowania oprogramowania. Jeśli twoje oprogramowanie jest dobrze zaprojektowane, powinieneś być w stanie wyodrębnić części oprogramowania i przepisać je w razie potrzeby, bez uszkadzania innych części systemu. Poza tym, większość prawdziwych przypadków optymalizacji, z którymi się spotkałem (ignorując niektóre prawdziwe sztuczki niskiego poziomu, są one przypadkowe) polegała na zmianie z jednego algorytmu na inny lub buforowaniu danych do pamięci zamiast dysku / sieci.

Erik van Brakel
źródło
1

Czytelność jest PIERWSZYM celem.

W latach siedemdziesiątych armia przetestowała niektóre z ówczesnych „nowych” technik tworzenia oprogramowania (projektowanie odgórne, programowanie strukturalne, główne zespoły programistów, by wymienić tylko kilka), aby określić, która z nich spowodowała statystycznie istotną różnicę.

JEDYNĄ techniką, która spowodowała statystycznie istotną różnicę w rozwoju, była ...

DODAWANIE PUSTYCH LINII do kodu programu.

Poprawa czytelności w tym wstępnie ustrukturyzowanym kodzie zorientowanym obiektowo była jedyną techniką w tych badaniach, która poprawiła produktywność.

==============

Optymalizacją należy zająć się tylko wtedy, gdy cały projekt jest testowany jednostkowo i gotowy do oprzyrządowania. Nigdy nie wiadomo, GDZIE trzeba zoptymalizować kod.

W swoich przełomowych książkach Kernigan i Plauger w późnych latach siedemdziesiątych SOFTWARE TOOLS (1976) i SOFTWARE TOOLS IN PASCAL (1981) pokazali sposoby tworzenia programów strukturalnych przy użyciu projektowania odgórnego. Stworzyli programy do przetwarzania tekstu: edytory, narzędzia wyszukiwania, preprocesory kodu.

Kiedy zakończona funkcja formatowania tekstu została ZINSTRUMENTOWANA, odkryli, że większość czasu przetwarzania została spędzona na trzech procedurach, które wykonywały wprowadzanie i wyprowadzanie tekstu (w oryginalnej książce funkcje io zajmowały 89% czasu. W książce pascal te funkcje skonsumował 55%!)

Udało im się zoptymalizować TRZY procedury i uzyskać wyniki w postaci zwiększonej wydajności przy rozsądnym, łatwym do zarządzania czasie i kosztach rozwoju.

SystemSmith
źródło
1

Czytelność przede wszystkim. Ale nawet więcej niż czytelność to prostota, szczególnie pod względem struktury danych.

Przypomina mi się student wykonujący program analizy wzroku, który nie mógł zrozumieć, dlaczego był taki wolny. Po prostu postępował zgodnie z dobrą praktyką programistyczną - każdy piksel był obiektem i działał, wysyłając wiadomości do swoich sąsiadów ...

Sprawdź to

Mike Dunlavey
źródło
1

Jeśli nie ma czytelności, bardzo trudno będzie uzyskać poprawę wydajności, gdy naprawdę tego potrzebujesz.

Wydajność należy poprawić tylko wtedy, gdy jest to problem w twoim programie, jest wiele miejsc, w których może być wąska szyjka, a nie ta składnia. Powiedzmy, że zmniejszasz 1ns poprawę w stosunku do <<, ale zignorujesz 10 minut czasu IO.

Ponadto, jeśli chodzi o czytelność, profesjonalny programista powinien umieć czytać / rozumieć terminy informatyczne. Na przykład możemy nazwać metodę umieszczoną w kolejce zamiast mówić putThisJobInWorkQueue.

Yuan
źródło
Chociaż zgadzam się, myślę, że masz kiepski przykład. Na przykład, jako ktoś, kto nic nie wie o twoim kodzie, kolejkowanie ma dla mnie mniejsze znaczenie. Nie chcę wiedzieć jak, chcę wiedzieć co. Przykład, który podałeś, mówi o tym, co jest znacznie lepsze.
Shaun Sweet
0

Najpierw pisz dla czytelności, ale oczekuj, że czytelnicy będą programistami . Każdy programista warty swojej uwagi powinien znać różnicę między mnożeniem a przesunięciem bitowym, lub umieć odczytać operator trójskładnikowy tam, gdzie jest on odpowiednio używany, być w stanie wyszukać i zrozumieć złożony algorytm (komentujesz swój kod, prawda? ) itp.

Wczesna nadmierna optymalizacja jest oczywiście dość kiepska, jeśli chodzi o wpadanie w kłopoty później, kiedy zajdzie potrzeba refaktoryzacji, ale tak naprawdę nie dotyczy to optymalizacji poszczególnych metod, bloków kodu lub instrukcji.

wprl
źródło
0

Powiedziałbym, że postaw na czytelność.

Ale w podanym przykładzie myślę, że druga wersja jest już wystarczająco czytelna, ponieważ nazwa funkcji dokładnie określa, co się dzieje w funkcji.

Gdybyśmy zawsze mieli funkcje, które mówią nam, co robią ...

Dan Soap
źródło
0

Ile kosztuje godzina czasu procesora?

Ile kosztuje godzina czasu programisty?

Andy Lester
źródło
1
ile kosztuje godzina czasu użytkownika końcowego? teraz pomnóż to przez liczbę użytkowników.
gbjbaanb
gbjbaanb: Dokładnie moje myśli. Komentarz Andy'ego działa tylko w przypadku usług, których użytkownik końcowy nigdy nie zobaczy, a nawet wtedy nie jest to dobre porównanie.
Erik van Brakel
0

IMHO obie rzeczy nie mają nic wspólnego. Najpierw powinieneś wybrać kod, który działa, ponieważ jest to ważniejsze niż wydajność lub to, jak dobrze się czyta. Odnośnie czytelności: Twój kod powinien być zawsze czytelny w każdym przypadku.

Jednak nie rozumiem, dlaczego kod nie jest czytelny i jednocześnie zapewnia dobrą wydajność. W twoim przykładzie druga wersja jest dla mnie tak samo czytelna jak pierwsza. Co jest w nim mniej czytelne? Jeśli programista nie wie, że przesunięcie w lewo to to samo, co pomnożenie przez potęgę dwóch, a przesunięcie w prawo to to samo, co podzielenie przez potęgę dwóch ... cóż, to masz znacznie więcej podstawowych problemów niż ogólna czytelność.

Mecki
źródło