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?
źródło
Odpowiedzi:
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.
źródło
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
Pixel
lubBoolean
.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
Pixel
lubBoolean
instancji) 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ą.
źródło
--force
d 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