Co powoduje, że duży i złożony produkt jest wolny? [Zamknięte]

16

Z powodu w dużej mierze nieistotnego ponownie zainstalowałem Delphi 7 w tak długim czasie. Muszę powiedzieć, że byłem całkowicie zdumiony - w pewnym sensie od dłuższego czasu. Nie tak w ogóle pamiętam. Instalacja zajęła około 30 sekund. Uruchomienie trwało 2 sekundy i było natychmiast możliwe do użycia. Mogę nacisnąć „Uruchom” sekundę po uruchomieniu, a niecałą sekundę później pusty program jest już widoczny i działa. Hurra, ponieważ komputery stają się znacznie szybsze!

Ale powodem, dla którego zostałem tak zachwycony, jest to, że zwykle używam Visual Studio 2010, co wcale nie jest takie głupie. To prawda, Delphi 7 jest znacznie mniejszy niż układ Visual Studio 2010, ale ma mieć wygląd posiadania wszystkich tam naprawdę niezbędne rzeczy: palety sterowania, projektant formularza, edytor kodu z zakończenia kodu. Zdaję sobie sprawę, że język może być prostszy, a uzupełnianie kodu może być znacznie mniej wydajne, a IDE może nie być tak rozszerzalne i bogate w funkcje, ale nadal: Nie rozumiem, jak (tj. Za pomocą jakiego mechanizmu) mieć wiele dodatkowych funkcji (których mogłem nawet nie uruchomić) powoduje, że system taki jak Visual Studio zawsze czuje się powolny w porównaniu z innymi.

Chciałbym zapytać ludzi doświadczonych w pracy z systemami w skali Visual Studio: co sprawia, że ​​są powolni? Czy to warstwa po warstwie abstrakcji jest niezbędna do utrzymania bazy kodu w zakresie możliwości ludzkiego rozumienia? Czy to właśnie ilość kodu musi zostać uruchomiona? Czy jest to współczesna tendencja do oszczędzania czasu przez programistę przy (ogromnie ogromnym) wydatku w dziale cykli zegara / wykorzystania pamięci?

Roman Starkov
źródło
7
Proste: wraz ze wzrostem masy potrzeba więcej siły, aby pokonać bezwładność.
Shog9,
Ktoś kiedyś powiedział mi menedżerów, ale w to nie wierzę.
MIchael Grassman
1
Jest to duża część powodu, dla którego wciąż używam D7 do programowania w Delphi.
GrandmasterB
Najszybszy kod to taki, który nigdy nie zostanie wykonany.
Henry
4
@romkyns: Uważam, że wiele oprogramowania we współczesnej erze jest często bardzo rozdęte, niepotrzebnie duże i nieporęczne. Wiele oprogramowania rozwiązuje teraz te same problemy, które zostały rozwiązane dziesięć, nawet dwadzieścia lat temu, z ułamkiem mocy i przestrzeni. Dlaczego nadal jest tak opóźniony, jak nigdy dotąd? Nieskuteczność i wzdęcia.
Orbling

Odpowiedzi:

20

Astronautyka architektoniczna

Visual Studio 2010 jest oparty na Windows Presentation Foundation. Spójrz na klasę przycisku dla WPF. Jest to dziewiąte dziecko klasy podstawowej. Ma około 5 stron właściwości, metod i zdarzeń. Za kulisami ma jeszcze pięć stron definicji stylów, które opisują jego pięknie zaokrąglone rogi i subtelne animacje, gdy przesuwa się nad nim kursor myszy. Wszystko to dotyczy czegoś, co zasadniczo wyświetla tekst lub obraz i powoduje zdarzenie kliknięcia, gdy wykryje opuszczanie przycisku myszy.

Zatrzymaj program taki jak Visual Studio w dowolnym losowym punkcie. Spójrz na ślad stosu. Są bardzo duże szanse, że masz 20 poziomów głęboko w stosie wywołań i że załadowano pięć bibliotek DLL, aby się tam dostać.

Teraz porównaj te dwie rzeczy z Delphi. Założę się, że okaże się, że przycisk Delphi ma tylko 20 właściwości, metod i zdarzeń. Założę się, że Delphi IDE ma tylko ślad stosu o głębokości 5-7 poziomów. Ponieważ gdy komputery działały wolniej, po prostu nie można było obciążyć Visual Studio 2010 bez uruchomienia IDE przez 40 minut :-)

Czy jedno jest lepsze od drugiego? Cóż, ogólnie mogę powiedzieć programowi Delphi, kiedy się ładuje, ponieważ wygląda płasko, kolory są wyciszone (być może 8 bitów?) I nie ma subtelnego cieniowania ani animacji. Po prostu czuję się teraz „tanio”. Tani, ale szybki.

Czy jest nam lepiej? To pytanie do filozofów, a nie do programistów.

Jay Beavers
źródło
4
Program delphi nie wygląda na płaski. Zamiast tego programista programuje program, aby wyglądał płasko. Za pomocą Delphi możesz tworzyć ładnie wyglądające, nowoczesne, pełnokolorowe interfejsy, tak jak w C # lub C ++.
GrandmasterB
2
To wnikliwa odpowiedź; ale nie jestem pewien, czy jest kompletny. Visual Studio 2008 (poprzednik 2010) nie ma WPF i wciąż jest wolniejszy niż Delphi 7. Czy nadal powiedziałbyś to samo o głębokości stosu wywołań i liczbie załadowanych bibliotek DLL?
Timwi
3
@Timwi Tak, absolutnie chciałbym. Nie chodziło mi o zło WPF (tak naprawdę lubię WPF), a raczej o to, jak mamy tendencję do dodawania warstw po warstwach abstrakcji oprogramowania, kiedy mamy wybór. Być może Visual Studio 2008 nie miał tak dużego obciążenia, ale jak zauważyłeś, miał dość :-)
Jay Beavers
@GrandmasterB, nie zatrzaskuję Delphi, ponieważ ma mniej założeń i prostsze biblioteki. WPF został zaprojektowany przy założeniu, że przyspieszenie sprzętowe GPU pozwoli programom na stosowanie głębszych kolorów, częstych animacji, mieszania alfa, cieni itp. Delphi zostało zaprojektowane w czasie, gdy nie można było przyjąć takich założeń. Czy możesz to wszystko zaimplementować w Delphi? Jasne, ale trzeba by wprowadzić dużo kodowania, aby uzyskać zachowanie przycisku WPF. Plusem jest to, że przycisk Delphi nie zawiera wymagań procesora, pamięci i GPU, a przycisk WPF ma jedno z pytań, które było pytaniem @ OP.
Jay Beavers
10
Twój argument za płaskim i prostym interfejsem użytkownika został całkowicie unieważniony przez nowy „nowoczesny” interfejs użytkownika systemu Windows 10. Teraz mamy to wszystko, aby stworzyć płaskie, kwadratowe, proste przyciski, jak mieliśmy 30 lat temu.
gbjbaanb
11

Chciałbym zapytać ludzi doświadczonych w pracy z systemami w skali Visual Studio: co sprawia, że ​​są powolni? Czy to warstwa po warstwie abstrakcji jest niezbędna do utrzymania bazy kodu w zakresie możliwości ludzkiego rozumienia? Czy to właśnie ilość kodu musi zostać uruchomiona? Czy jest to współczesna tendencja do oszczędzania czasu przez programistę przy (ogromnie ogromnym) wydatku w dziale cykli zegara / wykorzystania pamięci?

Myślę, że zgadłeś kilka z nich, ale chciałbym zaoferować coś, co uważam za największy czynnik, pracując na dość dużej bazie kodu (nie jestem pewien, czy jest tak duży jak Visual Studio - był w milionach linii kodu kategoria i około tysiąca wtyczek) przez około 10 lat i obserwowane są zjawiska.

Jest również nieco mniej kontrowersyjny, ponieważ nie wchodzi w interfejsy API, funkcje językowe ani nic podobnego. Dotyczą one „kosztów”, które mogą zapoczątkować debatę, a nie „wydatków”, a ja chcę się skoncentrować na „wydatkach”.

Luźna koordynacja i dziedzictwo

Zauważyłem, że luźna koordynacja i długa spuścizna prowadzą do gromadzenia dużej ilości odpadów.

Na przykład w tej bazie kodu znalazłem około stu struktur przyspieszenia, z których wiele jest zbędnych.

Chcielibyśmy drzewa drzewa KD do przyspieszania jednego silnika fizyki, drugiego dla nowego silnika fizyki, który często działał równolegle ze starym, mielibyśmy dziesiątki implementacji oktetów dla różnych algorytmów siatki, innego drzewa KD do renderowania , zbieranie itp. itd. Są to duże, nieporęczne struktury drzewa używane do przyspieszania wyszukiwania. Każdy z nich może zabrać setki megabajtów do gigabajtów pamięci dla danych wejściowych bardzo średniej wielkości. Nie zawsze były tworzone i używane przez cały czas, ale w dowolnym momencie 4 lub 5 z nich mogło być jednocześnie w pamięci.

Teraz wszystkie z nich przechowywały dokładnie te same dane, aby przyspieszyć ich wyszukiwanie. Możesz to sobie wyobrazić jako analogiczną starą bazę danych, która przechowuje wszystkie swoje pola jednocześnie w 20 różnych nadmiarowych mapach / słownikach / drzewach B +, uporządkowanych identycznie według tych samych kluczy i przeszukując je wszystkie przez cały czas. Teraz zajmujemy 20 razy więcej pamięci i przetwarzania.

Ponadto, ze względu na nadmiarowość, nie ma czasu na optymalizację żadnego z nich z ceną serwisową, która jest z tym związana, a nawet gdybyśmy to zrobili, miałby tylko 5% efektu, który idealnie by zrobił.

Co powoduje to zjawisko? Luźna koordynacja była przyczyną numer jeden, którą widziałem. Wielu członków zespołu często pracuje w swoich izolowanych ekosystemach, rozwijając lub wykorzystując struktury danych stron trzecich, ale nie używając tych samych struktur, z których korzystali inni członkowie zespołu, nawet jeśli byli rażącymi duplikatami tych samych obaw.

Co powoduje utrzymywanie się tego zjawiska? Dziedzictwo i kompatybilność były numerem jeden, ponieważ widziałem. Ponieważ ponieśliśmy już koszty wdrożenia tych struktur danych, a od tych rozwiązań zależały duże ilości kodu, często zbyt ryzykowne było ich skonsolidowanie do mniejszej liczby struktur danych. Mimo że wiele z tych struktur danych było wysoce redundantnych koncepcyjnie, nie zawsze były one identyczne w swoich projektach interfejsów. Zastąpienie ich byłoby dużą, ryzykowną zmianą, w przeciwieństwie do po prostu pozwalania im zużywać pamięć i czas przetwarzania.

Wydajność pamięci

Zazwyczaj użycie pamięci i szybkość są zwykle powiązane przynajmniej na poziomie hurtowym. Często można wykryć wolne oprogramowanie po tym, jak zapycha pamięć. Nie zawsze jest prawdą, że więcej pamięci prowadzi do spowolnienia, ponieważ liczy się pamięć „gorąca” (jaka pamięć jest dostępna przez cały czas - jeśli program używa dużej ilości pamięci, ale tylko 1 megabajt jest używany przez cały czas) czas, to nie jest tak wielka sprawa pod względem szybkości).

Możesz więc często wykryć potencjalne wieprze na podstawie zużycia pamięci. Jeśli aplikacja zabiera dziesiątki do setek megabajtów pamięci podczas uruchamiania, prawdopodobnie nie będzie bardzo wydajna. Dziesiątki megabajtów mogą wydawać się małe, gdy mamy gigabajty pamięci DRAM, ale największe i najwolniejsze pamięci podręczne procesora nadal znajdują się w wąskim zakresie megabajtów, a najszybsze wciąż w zakresie kilobajtów. W rezultacie program, który używa 20 megabajtów tylko do uruchomienia i nic nie robi, w rzeczywistości nadal zużywa dość „dużo” pamięci z punktu widzenia sprzętowej pamięci podręcznej procesora, zwłaszcza jeśli wszystkie 20 megabajtów tej pamięci będzie dostępne wielokrotnie i często w trakcie działania programu.

Rozwiązanie

Dla mnie rozwiązaniem jest poszukiwanie bardziej skoordynowanych, mniejszych zespołów do tworzenia produktów, takich, które mogą w pewien sposób śledzić swoje „wydatki” i unikać „kupowania” tych samych produktów w kółko.

Koszt

Zajmę się bardziej kontrowersyjną stroną „kosztu” tylko trochę z małym zjawiskiem „wydawania”, które zaobserwowałem. Jeśli w końcu pojawia się język z nieuniknioną ceną dla obiektu (na przykład taką, która zapewnia odbicie w czasie wykonywania i nie może wymusić ciągłego przydziału dla serii obiektów), ta cena jest droga tylko w kontekście bardzo ziarnistego elementu, takiego jak pojedynczy Pixellub Boolean.

Jednak widzę dużo kodu źródłowego dla programów, które radzą sobie z dużym obciążeniem (np. Radzenie sobie z setkami tysięcy do milionów Pixellub Booleaninstancji) płacącymi ten koszt na tak szczegółowym poziomie.

Programowanie obiektowe może to zaostrzyć. Jednak nie jest to koszt „obiektów” per se, ani nawet OOP z winy, to po prostu, że takie koszty są płacone na tak szczegółowym poziomie drobnego elementu, który zostanie utworzony przez miliony.

To inne zjawiska związane z „kosztem” i „wydawaniem”, które obserwuję. Koszt to pensy, ale pensy sumują się, jeśli kupujemy milion puszek z napojem osobno, zamiast negocjować z producentem na zakup hurtowy.

Rozwiązaniem dla mnie jest zakup „masowy”. Przedmioty są doskonale w porządku, nawet w językach, w których każdy ma pewną cenę grosza, pod warunkiem, że koszt ten nie jest płacony milion razy osobno za analogiczny ekwiwalent napoju gazowanego.

Przedwczesna optymalizacja

Nigdy nie podobało mi się użyte tutaj sformułowanie Knuth, ponieważ „przedwczesna optymalizacja” rzadko przyspiesza rzeczywiste programy produkcyjne. Niektórzy interpretują to jako „wczesną optymalizację”, gdy Knuth miał na myśli bardziej „optymalizację bez odpowiedniej wiedzy / doświadczenia, aby poznać jego prawdziwy wpływ na oprogramowanie”. Co więcej, praktyczny efekt prawdziwej przedwczesnej optymalizacji często powoduje spowolnienie oprogramowania , ponieważ pogorszenie możliwości konserwacji oznacza, że ​​nie ma czasu na optymalizację najważniejszych ścieżek, które są naprawdę ważne .

To ostatnie zjawisko, które zaobserwowałem, gdy programiści starali się zaoszczędzić grosze na zakupie jednej puszki napoju gazowanego, nigdy więcej nie do kupienia lub, co gorsza, domu, marnowali cały czas na szczypanie groszy niezrozumienie ich kompilatora lub architektury sprzętu), gdy miliardy dolarów wydawano gdzie indziej.

Czas jest bardzo skończony, więc próba optymalizacji absolutów bez posiadania odpowiednich informacji kontekstowych często pozbawia nas możliwości optymalizacji miejsc, które naprawdę mają znaczenie, a zatem pod względem praktycznym powiedziałbym, że „przedwczesna optymalizacja powoduje, że oprogramowanie jest znacznie wolniejsze. „

Problem polega na tym, że istnieją typy programistów, którzy wezmą to, co napisałem powyżej o obiektach i spróbują ustanowić standard kodowania, który zakazuje programowania obiektowego lub czegoś takiego szalonego. Skuteczna optymalizacja to skuteczne ustalanie priorytetów i absolutnie bezwartościowe, jeśli toniemy w morzu problemów związanych z konserwacją.

Thomas Owens
źródło
2
Innymi słowy, dług techniczny. Dług techniczny, który nigdy nie jest spłacany.
Robert Harvey
1
Robert ma rację. Jedna pomyłka faceta, dwieście błędów --forced popełnianych przez menedżerów krzyczących „zostaniesz zwolniony, jeśli nie zaimplementujesz tego do jutra”, które niszczą lata dobrych praktyk inżynierii oprogramowania, TDD, testów jednostkowych i wszelkich zasad programowania ludzkiego i zdrowego rozsądku plus dwa razy byłeś zmęczony ... ten facet, który opuścił firmę szalony, ponieważ został zwolniony bez powodu i popsuł bazę kodów .. te przestarzałe biblioteki, których nigdy nie aktualizowałeś ... a oto masz: pyszne spaghetti i wzdęte oprogramowanie. Bon appetit
użytkownik3834459,
2
Interesujące, zwłaszcza w tym, jak postrzegałeś nadmierne rozdrabnianie w niewłaściwy sposób. W przeszłości przyłapałem się na robieniu czegoś podobnego i w rezultacie miałem słabą wydajność. Jest to dość podobne do twojej odpowiedzi z kilku dni temu na temat korzystania z kolekcji i algorytmów zbiorczych zamiast preferencji . Nie mogę uwierzyć, że odpowiedź nie była bardziej doceniana ze względu na jej głębię. Zmusza mnie to do przemyślenia kilku projektów, które budowałem przez lata. Zastanawiam się, dlaczego te techniki nie są szerzej promowane?
Mike wspiera Monikę
2
@Mike Jestem trochę pobity, jeśli chodzi o próbę promowania sposobu myślenia opartego na danych. Jest popularny w branży gier, w której starają się wykorzystać każdy cal sprzętu. To powiedziawszy, co prawda zmniejsza elastyczność. Jeśli masz abstrakcyjną klasę pikseli, możesz robić szalone rzeczy, na przykład mieć pojedynczy obraz, który miesza dwa lub więcej różnych formatów pikseli! Jednak gdy mamy do czynienia z krytycznymi ścieżkami, prawdopodobnie żaden obraz nie skorzystałby z tego poziomu elastyczności, a wydajność zaczyna stawać się prawdziwym zmartwieniem dla wszystkiego, co dotyczy obrazów i pikseli.
1
W dawnych, złych czasach zaimplementowałem trochę kodu, aby ominąć interfejsy API grafiki i uzyskać bezpośredni dostęp do pikseli w pamięci dla krytycznego fragmentu mojego kodu. Różnica między wieloma warstwami abstrakcji i bezpośrednim dostępem wynosiła około 100x, co w tamtych czasach miało znaczenie na komputerze. Teraz komputery są na tyle szybkie, że możesz prześlizgiwać się przez dowolną ilość abstrakcji, jeśli musisz.
Michael Shopsin