Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00441 007531 11261422 na godz. na dobę w sumie
C++ Optymalizacja kodu - ebook/pdf
C++ Optymalizacja kodu - ebook/pdf
Autor: Liczba stron:
Wydawca: Promise Język publikacji: polski
ISBN: 978-83-7541-337-3 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie
Porównaj ceny (książka, ebook, audiobook).

We współczesnym świecie, pełnym pośpiechu i rywalizacji, wydajność programu jest równie istotna dla klientów, jak oferowane przez niego funkcje. Ten praktyczny podręcznik wyjaśnia podstawowe zasady podnoszenia wydajności, które pomagają w optymalizacji kodu C++. Uczy, jak dostosowywać poprawny kod C++ tak, aby działał on szybciej i zużywał mniej zasobów na każdym komputerze, począwszy od zegarka, poprzez telefon, stację roboczą, superkomputer, aż po globalną sieć serwerów.
Autor Kurt Guntheroth prezentuje szereg przykładów demonstrujących, w jaki sposób można, stopniowo wdrażając przedstawione zasady, osiągnąć kod spełniający wymagania klientów dotyczące reaktywności i przepustowości. O przydatności porad zamieszczonych w tej książce będzie się można przekonać, gdy kolega z zespołu zawoła: „Zaczęło działać niesamowicie szybko. Kto coś naprawił?”
Dowiedz się jak:
•    Wyznaczać kandydatów do optymalizacji przy użyciu programu profilującego oraz czasomierzy programowych
•    Przeprowadzać powtarzalne eksperymenty w celu mierzenia wydajności zmodyfikowanych wersji kodu
•    Optymalizować użycie zmiennych dynamicznych
•    Podnieść wydajność kosztownych pętli i funkcji
•    Przyspieszyć działanie funkcji przetwarzających ciągi
•    Rozpoznawać efektywne algorytmy i wzorce optymalizacyjne
•    Identyfikować mocne i słabe strony klas kontenerów w C++
•    Analizować wyszukiwanie i sortowanie z perspektywy optymalizatora
•    W efektywny sposób używać funkcji przesyłania strumieniowego we/wy w języku C++
•    W wydajny sposób stosować w kodzie C++ funkcje równoległe bazujące na wątkach
„    Cenne źródło praktycznych porad — aktualnych, trafnych i osadzonych w rzeczywistości. Solidne kompendium wiedzy o nowym obliczu języka C++.”
—Jerry Tan
Starszy programista,
The Depository Trust & Clearing Corporation
Kurt Guntheroth, programista z ponad 35-letnim doświadczeniem, od ćwierćwiecza zajmuje się opracowywaniem wydajnego kodu C++. Rozwija programy dla platform Windows, Linux oraz systemów wbudowanych. Kurt mieszka w Seattle w stanie Waszyngton.

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

C++ Optymalizacja kodu Kurt Guntheroth przekład: Natalia Chounlamany APN Promise Warszawa 2016 ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== C++. Optymalizacja kodu © 2016 APN PROMISE SA Authorized translation of English edition of Optimized C++ ISBN 978-1-491-92206-4 Copyright © 2016 Kurt Guntheroth. All rights reserved. This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls of all rights to publish and sell the same. APN PROMISE SA, ul. Domaniewska 44a, 02-672 Warszawa tel. +48 22 35 51 600, fax +48 22 35 51 699 e-mail: mspress@promise.pl Wszystkie prawa zastrzeżone. Żadna część niniejszej książki nie może być powielana ani rozpowszechniana w jakiejkolwiek formie i w jakikolwiek sposób (elektroniczny, mechaniczny), włącznie z fotokopiowaniem, nagrywaniem na taśmy lub przy użyciu innych systemów bez pisemnej zgody wydawcy. Logo O’Reilly jest zarejestrowanym znakiem towarowym O’Reilly Media, Inc. Optimized C++, ilustracja z okładki i powiązane elementy są znakami towarowymi O’Reilly Media, Inc. Wszystkie inne nazwy handlowe i towarowe występujące w niniejszej publikacji mogą być znakami towarowymi zastrzeżonymi lub nazwami zastrzeżonymi odpowiednich firm odnośnych właścicieli. Przykłady firm, produktów, osób i wydarzeń opisane w niniejszej książce są fikcyjne i nie odnoszą się do żadnych konkretnych firm, produktów, osób i wydarzeń. Ewentualne podobieństwo do jakiejkolwiek rzeczywistej firmy, organizacji, produktu, nazwy domeny, adresu poczty elektronicznej, logo, osoby, miejsca lub zdarzenia jest przypadkowe i niezamierzone. APN PROMISE SA dołożyła wszelkich starań, aby zapewnić najwyższą jakość tej publikacji. Jednakże nikomu nie udziela się rękojmi ani gwarancji. APN PROMISE SA nie jest w żadnym wypadku odpowiedzialna za jakiekolwiek szkody będące następstwem korzystania z informacji zawartych w niniejszej publikacji, nawet jeśli APN PROMISE została powiadomiona o możliwości wystąpienia szkód. ISBN: 978-83-7541-191-1 Projekt okładki: Randy Comer Ilustracje: Rebecca Demarest Przekład: Natalia Chounlamany Redakcja: Marek Włodarz Korekta: Ewa Swędrowska Skład i łamanie: MAWart Marek Włodarz ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Ponieważ wszyscy dziękują swoim współmałżonkom za wsparcie podczas pisania książki, brzmi to jak pusty slogan. Jednak moja żona Renee Ostler naprawdę umożliwiła powstanie tej książki. Pozwoliła mi wziąć kilkumie- sięczny urlop, znalazła czas i przestrzeń, które pozwoliły mi skoncentrować się na pisaniu, a nawet zarywała noce, aby zadawać mi pytania dotyczące optymalizacji kodu C++, mimo iż temat ten nieszczególnie ją interesuje. Wszystko po to, aby udzielić mi wsparcia. Projekt ten stał się istotny dla niej, ponieważ był ważny dla mnie. To największy dar dla autora. ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Spis treści Przedmowa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xv Potencjalne problemy z kodem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvi Korzystanie z przykładowego kodu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvii Konwencje użyte w tej książce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xviii 1 Wprowadzenie do optymalizacji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Optymalizacja to część procesu rozwoju oprogramowania. . . . . . . . . . . . . . . . . .2 Optymalizacja jest efektywna . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 Optymalizacja jest OK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4 Nanosekunda tu, nanosekunda tam . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6 Podsumowanie strategii optymalizacji kodu C++ . . . . . . . . . . . . . . . . . . . . . . . . .7 Użyj lepszego kompilatora, lepiej używaj kompilatora. . . . . . . . . . . . . . . . . .7 Użyj lepszych algorytmów . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9 Użyj lepszych bibliotek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .10 Zredukuj alokację pamięci i kopiowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . .11 Usuń obliczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12 Użyj lepszych struktur danych . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12 Zwiększ równoległość . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13 Zoptymalizuj zarządzanie pamięcią . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13 Podsumowanie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13 2 Wpływ działania komputera na optymalizację . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Nieprawdziwe przekonania języka C++ o komputerach . . . . . . . . . . . . . . . . . . .16 Prawda o komputerach. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .17 Pamięć jest powolna . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .17 Dostęp do pamięci nie zamyka się w bajtach. . . . . . . . . . . . . . . . . . . . . . . . .18 Nie wszystkie operacje dostępu do pamięci są równie wolne . . . . . . . . . . .19 Słowa mają najbardziej i najmniej znaczący koniec . . . . . . . . . . . . . . . . . . .20 Pamięć ma ograniczoną pojemność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21 Wykonanie instrukcji zabiera dużo czasu. . . . . . . . . . . . . . . . . . . . . . . . . . . .21 Komputery mają trudności z podejmowaniem decyzji . . . . . . . . . . . . . . . .22 Istnieje wiele strumieni wykonania programu . . . . . . . . . . . . . . . . . . . . . . .22 Wywoływanie systemu operacyjnego jest kosztowne. . . . . . . . . . . . . . . . . .24 C++ również kłamie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .24 Różne instrukcje mają różny koszt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25 Instrukcje nie są wykonywane kolejno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25 ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== v Podsumowanie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .26 3 Mierzenie wydajności . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Mentalność optymalizatora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .28 Wydajność musi być mierzona. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .28 Optymalizatorzy polują na grubą zwierzynę . . . . . . . . . . . . . . . . . . . . . . . . .29 Reguła 90/10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .29 Prawo Amdahla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .31 Przeprowadzanie eksperymentów. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .32 Prowadź notatnik laboratoryjny . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .34 Mierzenie bazowej wydajności i wyznaczanie celów . . . . . . . . . . . . . . . . . .35 Można poprawić tylko to, co zostało zmierzone . . . . . . . . . . . . . . . . . . . . . .37 Działanie programu profilującego. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .37 Pomiary czasowe długotrwałych zadań . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .40 „Odrobina wiedzy” o mierzeniu czasu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .41 Mierzenie czasu przy użyciu komputerów . . . . . . . . . . . . . . . . . . . . . . . . . . .46 Pokonywanie trudności w mierzeniu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .55 Tworzenie klasy stopera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .58 Mierzenie czasu aktywnych funkcji w warunkach testowych . . . . . . . . . . .63 Szacowanie kosztu kodu w celu znalezienia aktywnego kodu . . . . . . . . . . . . . .64 Szacowanie kosztu pojedynczych instrukcji C++ . . . . . . . . . . . . . . . . . . . . .64 Szacowanie kosztu pętli. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .65 Inne sposoby odnajdowania aktywnych punktów . . . . . . . . . . . . . . . . . . . . . . . .67 Podsumowanie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .68 4 Optymalizowanie użycia ciągów: przykład . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 Dlaczego ciągi są tak problematyczne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .69 Ciągi są dynamicznie alokowane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .70 Ciągi to wartości. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .71 Ciągi wymagają wiele kopiowania. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .71 Pierwsze podejście do optymalizacji ciągów . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73 Użyj operacji mutujących do eliminowania wartości tymczasowych. . . . .74 Redukuj realokację poprzez rezerwację obszaru . . . . . . . . . . . . . . . . . . . . . .75 Eliminuj kopiowanie argumentów std::string . . . . . . . . . . . . . . . . . . . . . . . .75 Eliminuj wyłuskania wskaźników przy użyciu iteratorów . . . . . . . . . . . . . .77 Eliminuj kopiowanie wartości zwrotnych . . . . . . . . . . . . . . . . . . . . . . . . . . .78 Użyj tablic znaków zamiast ciągów . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .79 Podsumowanie pierwszego podejścia do optymalizacji. . . . . . . . . . . . . . . .81 Drugie podejście do optymalizacji ciągów. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .81 Użyj lepszego algorytmu. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .81 Użyj lepszego kompilatora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .84 vi | Spis treści ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Użyj lepszej biblioteki ciągów. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .84 Użyj lepszego alokatora. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .88 Eliminowanie konwersji ciągów . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .90 Konwersja z ciągu C do std::string. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .90 Konwersja między kodowaniami znaków . . . . . . . . . . . . . . . . . . . . . . . . . . .91 Podsumowanie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .91 5 Optymalizowanie algorytmów . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 Koszt czasowy algorytmów . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .95 Koszt czasowy w najlepszym, średnim i najgorszym przypadku . . . . . . . .97 Amortyzowany koszt czasowy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .98 Inne koszty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .98 Zestaw narzędzi do optymalizacji wyszukiwania i sortowania. . . . . . . . . . . . . .98 Efektywne algorytmy wyszukiwania. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .99 Koszt czasowy algorytmów wyszukiwania. . . . . . . . . . . . . . . . . . . . . . . . . . .99 Wszystkie wyszukania są równie dobre dla małych n . . . . . . . . . . . . . . . .100 Efektywne algorytmy sortowania . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .101 Koszt czasowy algorytmów sortowania . . . . . . . . . . . . . . . . . . . . . . . . . . . .102 Zastąpienie algorytmów sortowania o niewydajnym najgorszym przypadku. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .102 Eksploatowanie znanych właściwości danych wejściowych. . . . . . . . . . . .103 Wzorce optymalizacji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .103 Wstępne obliczanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .104 Opóźnione obliczanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .105 Przetwarzanie wsadowe. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .106 Buforowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .106 Specjalizacja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .107 Pobieranie większych porcji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .107 Wskazówki . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .108 Optymalizowanie oczekiwanej ścieżki . . . . . . . . . . . . . . . . . . . . . . . . . . . . .108 Mieszanie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .108 Podwójne sprawdzanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .109 Podsumowanie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .109 6 Optymalizacja zmiennych dynamicznych . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 Powtórzenie wiadomości o zmiennych C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . .112 Czas magazynowania. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .112 Własność zmiennych. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .115 Obiekty wartości i obiekty encji. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .116 Powtórzenie wiadomości o API zmiennych dynamicznych w C++. . . . . . . . .117 ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Spis treści | vii Sprytne wskaźniki automatyzują zarządzanie własnością zmiennych dynamicznych . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .120 Dynamiczne zmienne wpływają na koszt czasowy wykonania. . . . . . . . .123 Redukowanie użycia zmiennych dynamicznych. . . . . . . . . . . . . . . . . . . . . . . . .124 Twórz instancje klas statycznie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .124 Używaj statycznych struktur danych. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .125 Użyj std::make_shared zamiast new . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .129 Nie dziel się własnością niepotrzebnie . . . . . . . . . . . . . . . . . . . . . . . . . . . . .130 Użyj „głównego wskaźnika” jako właściciela zmiennych dynamicznych 131 Redukowanie realokacji zmiennych dynamicznych. . . . . . . . . . . . . . . . . . . . . .132 Wstępnie alokuj zmienne dynamiczne, aby zapobiec realokacji. . . . . . . .132 Twórz zmienne dynamiczne poza pętlą . . . . . . . . . . . . . . . . . . . . . . . . . . . .133 Eliminowanie niepotrzebnego kopiowania . . . . . . . . . . . . . . . . . . . . . . . . . . . . .134 Wyłącz nieumyślne kopiowanie w definicji klasy . . . . . . . . . . . . . . . . . . . .135 Wyeliminuj kopiowanie podczas wywoływania funkcji. . . . . . . . . . . . . . .136 Wyeliminuj kopiowanie podczas powrotów z funkcji . . . . . . . . . . . . . . . .138 Biblioteki bez kopiowania. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .140 Implementuj idiom „kopiowanie przy zapisie” . . . . . . . . . . . . . . . . . . . . . .141 Stosuj wycinki struktur danych . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .142 Implementowanie semantyki przenoszenia. . . . . . . . . . . . . . . . . . . . . . . . . . . . .143 Niestandardowa semantyka kopiowania: desperackie rozwiązanie . . . . .143 std::swap(): semantyka przenoszenia dla ubogich. . . . . . . . . . . . . . . . . . . .144 Współwłasność encji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .145 Przenoszone części semantyki przenoszenia . . . . . . . . . . . . . . . . . . . . . . . .146 Uaktualnij kod w celu użycia semantyki przenoszenia. . . . . . . . . . . . . . . .148 Subtelności semantyki przenoszenia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .148 Spłaszczanie struktur danych. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .151 Podsumowanie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .152 7 Optymalizowanie aktywnych instrukcji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 Usuwanie kodu z pętli. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .154 Buforuj wartość końcową pętli. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .155 Użyj bardziej efektywnych instrukcji pętli . . . . . . . . . . . . . . . . . . . . . . . . . .155 Odliczaj w dół zamiast w górę . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .156 Usuń z pętli niezależny kod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .157 Usuń z pętli niepotrzebne wywołania funkcji . . . . . . . . . . . . . . . . . . . . . . .158 Usuń z pętli ukryte wywołania funkcji . . . . . . . . . . . . . . . . . . . . . . . . . . . . .161 Usuń z pętli kosztowne, wolno zmieniające się wywołania . . . . . . . . . . . .163 Przesuń pętle do funkcji, aby zredukować dodatkowy koszt wywołań . .164 Rzadziej wykonuj niektóre akcje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .165 A co z całą resztą?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .166 viii | Spis treści ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Usuwanie kodu z funkcji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .167 Koszt wywołań funkcji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .167 Deklaruj krótkie funkcje jako inline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .171 Definiuj funkcje przed pierwszym użyciem. . . . . . . . . . . . . . . . . . . . . . . . .172 Eliminuj niepotrzebny polimorfizm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .172 Usuń nieużywane interfejsy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .173 Wybieraj implementację w czasie kompilacji przy użyciu szablonów . . .177 Eliminuj zastosowania idiomu PIMPL . . . . . . . . . . . . . . . . . . . . . . . . . . . . .178 Eliminuj wywołania bibliotek DLL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .180 Użyj statycznych funkcji składowych zamiast funkcji składowych. . . . . .180 Przenieś wirtualny destruktor do klasy podstawowej. . . . . . . . . . . . . . . . .181 Optymalizowanie wyrażeń. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .182 Uprość wyrażenia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .182 Grupowanie stałych. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .184 Użyj mniej kosztownych operatorów . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .184 Używaj arytmetyki liczb całkowitych zamiast arytmetyki liczb zmiennoprzecinkowych . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .185 Typ double może być szybszy niż float . . . . . . . . . . . . . . . . . . . . . . . . . . . . .187 Zastąp obliczenia iteracyjne wzorami . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .187 Optymalizacja idiomów przepływu sterowania . . . . . . . . . . . . . . . . . . . . . . . . .189 Użyj switch zamiast if – else if – else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .189 Użyj funkcji wirtualnych zamiast switch lub if . . . . . . . . . . . . . . . . . . . . . .190 Korzystaj z bezkosztowej obsługi wyjątków. . . . . . . . . . . . . . . . . . . . . . . . .191 Podsumowanie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .193 8 Zastosowanie lepszych bibliotek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 Optymalizacja użycia biblioteki standardowej . . . . . . . . . . . . . . . . . . . . . . . . . .195 Filozofia standardowej biblioteki C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . .196 Problemy ze stosowaniem standardowej biblioteki C++ . . . . . . . . . . . . . .197 Optymalizowanie istniejących bibliotek. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .199 Zmieniaj tak mało, jak to tylko możliwe. . . . . . . . . . . . . . . . . . . . . . . . . . . .200 Dodawaj funkcje zamiast zmieniać funkcjonalność . . . . . . . . . . . . . . . . . .200 Projektowanie zoptymalizowanych bibliotek . . . . . . . . . . . . . . . . . . . . . . . . . . .201 Koduj szybko, ubolewaj w czasie wolnym . . . . . . . . . . . . . . . . . . . . . . . . . .201 W projektowaniu bibliotek ascetyzm to zaleta. . . . . . . . . . . . . . . . . . . . . . .202 Podejmuj decyzje o alokacji pamięci poza biblioteką. . . . . . . . . . . . . . . . .203 Programuj szybkie biblioteki . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .203 Łatwiej jest optymalizować funkcje niż framework . . . . . . . . . . . . . . . . . .204 Spłaszcz hierarchie dziedziczenia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .204 Spłaszcz łańcuchy wywołań . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .205 Spłaszcz wielowarstwowe projekty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .205 ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Spis treści | ix Unikaj dynamicznego wyszukiwania . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .206 Wystrzegaj się „wszechmocnych funkcji”. . . . . . . . . . . . . . . . . . . . . . . . . . .207 Podsumowanie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .209 9 Optymalizacja wyszukiwania i sortowania . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 Tabele klucz/wartość wykorzystujące std::map i std::string. . . . . . . . . . . . . . . .212 Zestaw narzędzi do podnoszenia wydajności wyszukiwania . . . . . . . . . . . . . .213 Dokonywanie bazowego pomiaru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .214 Zidentyfikuj aktywność do zoptymalizowania . . . . . . . . . . . . . . . . . . . . . .215 Rozłóż aktywność do zoptymalizowania . . . . . . . . . . . . . . . . . . . . . . . . . . .215 Zmodyfikuj lub zastąp algorytmy i struktury danych. . . . . . . . . . . . . . . . .216 Przeprowadź proces optymalizacji na niestandardowych abstrakcjach. .218 Optymalizowanie wyszukiwania przy użyciu std::map . . . . . . . . . . . . . . . . . . .219 Użyj tablic znaków o stałym rozmiarze w roli kluczy std::map . . . . . . . . .219 Użyj std::map z kluczami ciągu w stylu języka C. . . . . . . . . . . . . . . . . . . . .220 Użyj std::set dla kluczy zawartych w wartościach . . . . . . . . . . . . . . . . . . . .223 Optymalizowanie wyszukiwania przy użyciu nagłówka algorithm . . . . . . .224 Przeszukiwana tabela klucz/wartość w kontenerach sekwencji . . . . . . . .225 std::find(): oczywista nazwa, koszt czasowy O(n). . . . . . . . . . . . . . . . . . . .226 std::binary_search(): nie zwraca wartości. . . . . . . . . . . . . . . . . . . . . . . . . . .227 Wyszukiwanie binarne przy użyciu std::equal_range() . . . . . . . . . . . . . . .228 Wyszukiwanie binarne przy użyciu std::lower_bound() . . . . . . . . . . . . . .228 Własna implementacja wyszukiwania binarnego . . . . . . . . . . . . . . . . . . . .229 Własna implementacja wyszukiwania binarnego przy użyciu strcmp() .230 Optymalizowanie wyszukiwania w tabelach mieszania klucz/wartość . . . . . .231 Mieszanie przy użyciu std::unordered_map. . . . . . . . . . . . . . . . . . . . . . . . .232 Mieszanie, gdy klucze są tablicami o stałej liczbie znaków . . . . . . . . . . . .233 Mieszanie, gdy klucze są ciągami zakończonymi znakiem null . . . . . . . .234 Mieszanie z niestandardową tabelą . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .236 Konsekwencje abstrakcji Stepanova . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .237 Optymalizuj sortowanie przy użyciu standardowej biblioteki C++ . . . . . . . . .239 Podsumowanie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .240 10 Optymalizowanie struktur danych . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 Poznaj kontenery z biblioteki standardowej . . . . . . . . . . . . . . . . . . . . . . . . . . . .241 Kontenery sekwencji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .242 Kontenery asocjacyjne. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .242 Eksperymentowanie z kontenerami biblioteki standardowej . . . . . . . . . .243 std::vector i std::string. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .249 Wpływ realokacji na wydajność. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .250 Wstawianie i usuwanie z std::vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .251 x | Spis treści ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Iterowanie po kontenerze std::vector. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .253 Sortowanie kontenera std::vector. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .254 Przeszukiwanie kontenera std::vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .254 std::deque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .255 Wstawianie i usuwanie z std::deque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .256 Iterowanie po kontenerze std::deque. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .257 Sortowanie kontenera std::deque. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .258 Przeszukiwanie kontenera std::deque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .258 std::list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .259 Wstawianie i usuwanie z std::list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .261 Iterowanie po kontenerze std::list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .261 Sortowanie kontenera std::list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .262 Przeszukiwanie kontenera std::list. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .262 std::forward_list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .262 Wstawianie i usuwanie z std::forward_list . . . . . . . . . . . . . . . . . . . . . . . . . .264 Iterowanie po kontenerze std::forward_list . . . . . . . . . . . . . . . . . . . . . . . . .264 Sortowanie kontenera std::forward_list . . . . . . . . . . . . . . . . . . . . . . . . . . . .264 Przeszukiwanie kontenera std::forward_list. . . . . . . . . . . . . . . . . . . . . . . . .264 std::map i std::multimap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .264 Wstawianie i usuwanie z std::map. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .266 Iterowanie po kontenerze std::map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .268 Sortowanie kontenera std::map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .268 Przeszukiwanie kontenera std::map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .268 std::set i std::multiset. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .269 std::unordered_map i std::unordered_multimap . . . . . . . . . . . . . . . . . . . . . . . .270 Wstawianie i usuwanie z std::unordered_map . . . . . . . . . . . . . . . . . . . . . .274 Iterowanie po kontenerze std::unordered_map. . . . . . . . . . . . . . . . . . . . . .274 Przeszukiwanie kontenera std::unordered_map . . . . . . . . . . . . . . . . . . . . .274 Inne struktury danych. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .275 Podsumowanie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .277 11 Optymalizowanie we/wy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 Przepis na odczytywanie plików . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .279 Tworzenie ascetycznej sygnatury funkcji . . . . . . . . . . . . . . . . . . . . . . . . . . .281 Skracanie łańcucha wywoływania . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .283 Redukowanie realokacji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .283 Pobierz większe porcje – użyj większego bufora wejściowego. . . . . . . . . .286 Pobieraj większe porcje – odczytuj pojedyncze wiersze . . . . . . . . . . . . . . .286 Ponowne skracanie łańcucha wywołań. . . . . . . . . . . . . . . . . . . . . . . . . . . . .288 Zmiany, które nie pomogły. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .290 Zapisywanie plików. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .291 ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Spis treści | xi Odczytywanie z std::cin i zapisywanie w std::cout . . . . . . . . . . . . . . . . . . . . . . .292 Podsumowanie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .292 12 Optymalizowanie równoległości . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293 Powtórzenie informacji o równoległości . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .294 Wprowadzenie do świata równoległości. . . . . . . . . . . . . . . . . . . . . . . . . . . .295 Wykonanie z przeplotem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .299 Spójność sekwencyjna . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .300 Wyścigi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .301 Synchronizacja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .302 Atomowość . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .303 Powtórzenie informacji o obsłudze równoległości w języku C++ . . . . . . . . . .305 Wątki . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .305 Obietnice i przyszłości. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .307 Zadania asynchroniczne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .309 Mutexy. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .311 Blokady . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .312 Zmienne warunkowe. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .313 Atomowe operacje na współdzielonych zmiennych . . . . . . . . . . . . . . . . . .316 Plany: Przyszłość równoległości w języku C++. . . . . . . . . . . . . . . . . . . . . .319 Optymalizowanie wielowątkowych programów C++ . . . . . . . . . . . . . . . . . . . .321 Wybieraj std::async zamiast std::thread . . . . . . . . . . . . . . . . . . . . . . . . . . . .321 Dopasuj liczbę wątków do liczby rdzeni. . . . . . . . . . . . . . . . . . . . . . . . . . . .323 Implementuj kolejkę zadań i pulę wątków . . . . . . . . . . . . . . . . . . . . . . . . . .325 Wykonywanie operacji we/wy w osobnym wątku. . . . . . . . . . . . . . . . . . . .326 Program bez synchronizacji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .326 Usuwanie kodu z uruchamiania i zamykania. . . . . . . . . . . . . . . . . . . . . . . .329 Zwiększenie wydajności synchronizacji. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .330 Redukuj zakres sekcji krytycznych . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .330 Ograniczaj liczbę równoległych wątków. . . . . . . . . . . . . . . . . . . . . . . . . . . .331 Unikaj problemu masowego pędu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .332 Unikaj konwoju blokady . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .333 Zredukuj rywalizację . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .333 Nie oczekuj aktywnie w jednordzeniowym systemie . . . . . . . . . . . . . . . . .335 Nie czekaj w nieskończoność . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .335 Tworzenie własnego mutexu może być nieefektywne . . . . . . . . . . . . . . . .335 Ogranicz długość kolejki wyjściowej producenta . . . . . . . . . . . . . . . . . . . .336 Biblioteki wspierające równoległość . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .336 Podsumowanie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .338 xii | Spis treści ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== 13 Optymalizowanie zarządzania pamięcią . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339 Powtórzenie wiadomości o API zarządzania pamięcią w języku C++. . . . . . .340 Cykl życia zmiennych dynamicznych . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .340 Funkcje zarządzania pamięcią alokują i zwalniają pamięć. . . . . . . . . . . . .341 Wyrażenia new konstruują zmienne dynamiczne. . . . . . . . . . . . . . . . . . . .344 Wyrażenia delete usuwają zmienne dynamiczne. . . . . . . . . . . . . . . . . . . . .347 Jawne wywołania destruktora usuwają zmienne dynamiczne. . . . . . . . . .348 Wysoko wydajne menedżery pamięci. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .349 Dostarczanie menedżera pamięci specyficznego dla klasy . . . . . . . . . . . . . . . .351 Menedżer pamięci o stałym rozmiarze bloku . . . . . . . . . . . . . . . . . . . . . . .352 Arena bloków . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .355 Dodawanie specyficznego dla klasy operator new() . . . . . . . . . . . . . . . . .357 Wydajność menedżera pamięci o stałym rozmiarze bloku . . . . . . . . . . . .358 Różne warianty menedżera pamięci o stałym rozmiarze bloku . . . . . . . .359 Menedżery pamięci nieobsługujące wielowątkowości są wydajne . . . . . .360 Dostarczanie niestandardowych alokatorów. . . . . . . . . . . . . . . . . . . . . . . . . . . .360 Minimalny alokator C++11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .363 Dodatkowe definicje dla alokatora C++98. . . . . . . . . . . . . . . . . . . . . . . . . .365 Alokator o stałym rozmiarze bloków . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .369 Alokator o stałym rozmiarze bloków dla ciągów. . . . . . . . . . . . . . . . . . . . .371 Podsumowanie. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .373 Indeks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375 O autorze . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389 ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Spis treści | xiii ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Przedmowa Dzień dobry. Mam na imię Kurt i jestem kodoholikiem. Pisaniem kodu zajmuję się od ponad 35 lat. Nigdy nie pracowałem w Microsoft, Google, Facebook, Apple czy innej słynnej firmie. Jednak poza kilkoma krótkimi przerwami piszę kod każdego dnia. Ostatnie 20 lat poświęciłem prawie wyłącznie na rozwijanie kodu C++ oraz rozmawianie o języku C++ z innymi bardzo zdolnymi programistami. Tak wyglądają moje kwalifikacje do napisania książki o optymalizacji kodu C++. Posiadam również spore doświadczenie w pisaniu zwykłych tekstów, takich jak specyfikacje, komentarze, instrukcje, notatki czy wpisy na blogu (http://oldhandsblog.blogspot.com/). Ciągle dziwi mnie, że tylko połowa inteligentnych, kompetentnych programistów, z którymi miałem okazję współpracować, potrafi sklecić dwa poprawne zdania. Jeden z moich ulubionych cytatów pochodzi z listu Izaaka Newtona, w którym pisze on: „Jeśli widzę dalej, to tylko dlatego, że stoję na ramionach gigantów”. Ja także stoję na ramionach gigantów, a dokładniej przeczytałem ich książki: eleganckie i zwięzłe jak Język ANSI C. Programowanie Briana Kernighan i Dennisa Ritchie, mądre i postępowe jak seria Effective C++ Scotta Meyersa, ambitne i rozszerzające horyzonty jak Nowoczesne programowanie w C++ Andreia Alexandrescu, ostrożne i precyzyjne jak The Annotated C++ Reference Manual Bjarne Stroustrupa i Margaret Ellis. Przez długi czas nawet nie rozważałem możliwości zostania autorem, aż pewnego dnia, dość niespodziewanie, po- czułem potrzebę napisania tej książki. Dlaczego zdecydowałem się napisać książkę o podnoszeniu wydajności w języku C++? Na początku XXI wieku język C++ znajdował się pod ostrzałem. Fani języka C wskazy- wali programy C++, których wydajność była gorsza niż teoretycznie równoważnego kodu napisanego w języku C. Słynne korporacje poświęcały ogromne budżety na reklamowa- nie własnych języków obiektowych, twierdząc, że język C++ jest zbyt trudny w użyciu i to ich narzędzia będą przyszłością sektora informatycznego. Uniwersytety decydowały się na nauczanie języka Java, ponieważ oferował on darmowy zestaw narzędzi. W efekcie duże firmy zaczęły odwracać się od technologii C++, wybierając coraz częściej język Java, C# lub PHP do implementowania serwisów internetowych oraz systemów operacyjnych. Był to niepewny czas dla osób przekonanych o użyteczności i ogromnych możliwościach języka C++. Później jednak stała się rzecz niesłychana. Szybkość procesorów przestała rosnąć, mimo iż ich ilość pracy stale się zwiększała. Te same firmy zaczęły angażować programistów C++ ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== xv w rozwiązywanie problemów ze skalowaniem. Koszt przepisania kodu do języka C++ był często mniejszy niż koszt zasilania centrów danych. Nagle język C++ wrócił do łask. W odróżnieniu od innych języków powszechnie stosowanych na początku 2016 roku język C++ oferuje programistom pełne spektrum opcji implementacji, począwszy od zau- tomatyzowanego wsparcia bez konieczności nadzorowania po ścisłą kontrolę. Język C++ daje programistom ogromną swobodę w balansowaniu różnych aspektów wydajności. Tak wysoki stopień kontroli stwarza potencjał dla optymalizacji. Mało książek opisuje optymalizację kodu C++. Dostępna jest solidna, lecz nieco już przestarzała książka Efektywne programowanie w C++ Dova Bulki i Davida Mayhew. Jej autorzy mają doświadczenie podobne do mojego i doszli do wielu podobnych wniosków. Polecam ją czytelnikom, którzy chcieliby spojrzeć na omawiane w niniejszej książce prob- lemy z nieco innej perspektywy. Dodatkowo, Scott Meyers (jak również wielu innych) do- brze i szczegółowo omówił problem eliminowania wywołań konstruktorów kopiujących. Optymalizacja ma tak wiele aspektów, że można byłoby poświęcić jej nawet 10 książek. Dlatego musiałem wybrać te scenariusze, z którymi spotykam się najczęściej lub których optymalizacja może przynieść największe korzyści. Niektórzy czytelnicy posiadający do- świadczenie w usprawnianiu kodu C++ mogą uznać, że pominąłem pewne sprawdzone i użyteczne strategie. Jednak ze względu na ograniczoną pojemność książki musiałem dokonać wyboru. Zachęcam do przesyłania poprawek, komentarzy oraz ulubionych strategii optymali- zacji na adres: antelope_book@guntheroth.com. Uwielbiam rzemiosło, jakim jest rozwijanie oprogramowania. Mógłbym w nieskończo- ność ćwiczyć kata każdej nowej pętli lub interfejsu. Pisanie kodu podobnie jak pisanie wierszy to umiejętność tak ezoteryczna, sztuka tak osobista, że zrozumieć ją mogą tylko inni wtajemniczeni. W każdej elegancko napisanej funkcji znaleźć można piękno, podob- nie jak w każdym trafnie użytym idiomie mądrość. Niestety na każdy wybitny progra- mistyczny poemat, taki jak biblioteka Standard Template Library Stepanova, przypadają tysiące tomów nudnego, banalnego kodu. Ta książka ma przede wszystkim zwrócić uwagę wszystkich czytelników na piękno zoptymalizowanego oprogramowania. Przeczytajcie ją i wykorzystajcie. Spójrzcie dalej! Potencjalne problemy z kodem Chociaż od ponad 20 lat zajmuję się pisaniem i optymalizowaniem kodu C++, większość kodu przedstawionego w tej książce została napisana specjalnie z myślą o tej książce i tak jak każdy nowy projekt z pewnością zawiera błędy. Za co z góry przepraszam. Mam doświadczenie w programowaniu na platformę Windows, Linux oraz różne sy- stemy wbudowane. Prezentowany kod zostały opracowany z myślą o platformie Windows i dlatego, podobnie jak cała książka, kładzie szczególny nacisk na aspekty związane z sy- stemem Windows. Porady dotyczące optymalizacji kodu C++, choć zilustrowane przy użyciu narzędzia Visual Studio na platformie Windows, odnoszą się także do systemów xvi | Przedmowa ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Linux, Mac OS X czy innych środowisk C++. Jednak parametry czasowe poszczególnych technik optymalizacji zależą od implementacji kompilatora i standardowej biblioteki oraz od procesora, na którym testowany jest kod. Optymalizacja stanowi eksperymentalną dziedzinę wiedzy. Przyjmowanie na wiarę porad dotyczących optymalizacji może pocią- gać za sobą niepożądane skutki. Uzyskanie zgodności z różnymi kompilatorami oraz innymi systemami Unix i syste- mami wbudowanymi stanowi spore wyzwanie, dlatego przepraszam, jeśli przedstawiony kod nie kompiluje się w ulubionym systemie czytelnika. Ponieważ książka nie omawia zgodności między systemami, priorytetem było uzyskanie prostego kodu. Przedstawiony poniżej sposób formatowania wcięć kodu z nawiasami klamrowymi nie jest moim ulubionym: if (bool_condition) { controlled_statement(); } Osobiście preferuję umieszczanie otwierających i zamykających nawiasów klamrowych w oddzielnych wierszach. Jednak powyższy sposób umożliwia umieszczenie większej liczby wierszy na jednej stronie druku, zatem zdecydowałem się na zastosowanie go w ni- niejszej książce. Korzystanie z przykładowego kodu Materiały pomocnicze (przykładowy kod, rozwiązania itp.) są dostępne do pobrania na stronie www.guntheroth.com. Ta książka ma pomóc programistom w osiąganiu własnych celów. Dlatego wykorzy- stywanie przedstawionego przykładowego kodu w programach oraz dokumentacji jest zasadniczo dozwolone. Nie ma potrzeby kontaktowania się z nami w celu uzyskania ze- zwolenia, o ile nie planuje się reprodukcji znaczącej części kodu. Na przykład, napisanie programu wykorzystującego kilka fragmentów kodu z książki nie wymaga zezwolenia. Natomiast sprzedaż lub dystrybucja CD z przykładami wymaga zezwolenia. Udzielenie odpowiedzi poprzez zacytowanie tej książki i przykładowego kodu nie wymaga zezwole- nia. Umieszczenie znaczącej części przykładów kodu z tej książki w dokumentacji włas- nego produktu wymaga zezwolenia. Będziemy wdzięczni za wskazanie źródła, choć nie jest to wymagane. Przypis powi- nien zwykle zawierać nazwisko autora, tytuł, wydawnictwo oraz numer ISBN. Na przy- kład: „Kurt Guntheroth, C++. Optymalizacja kodu, O’Reilly/APN Promise, © 2016 Kurt Guntheroth, 978-83-7541-191-1”. W przypadku wątpliwości, czy planowane zastosowanie przykładowego kodu wykracza poza przedstawione powyżej zezwolenia, prosimy o skontaktowanie się z nami za pośred- nictwem adresu e-mail: permissions@oreilly.com. ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Korzystanie z przykładowego kodu | xvii Konwencje użyte w tej książce Oto konwencje typograficzne przyjęte w tej książce: Zwykły tekst Odnosi się do elementów, tytułów i opcji menu oraz klawiszy skrótów (takich jak Alt czy Ctrl). Kursywa Wyróżnia nowe terminy, adresy URL, adresy email, ścieżki, nazwy i rozszerzenia plików. Stała szerokość Służy do przedstawiania fragmentów kodu programu, a także do odwoływania się w tekście do elementów programu, takich jak nazwy zmiennych, funkcji i baz da- nych, typy danych, zmienne środowiskowe, instrukcje czy słowa kluczowe. xviii | Przedmowa ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Rozdział 1 Wprowadzenie do optymalizacji Świat ma niesamowity apetyt na moc obliczeniową. Pewne programy wymagają ciągłego i szybkiego działania niezależnie od tego, czy kod jest uruchamiany na zegarku, telefonie, tablecie, stacji roboczej, superkomputerze czy ogólnoświatowej sieci centrów danych. Dlatego czasem nie wystarcza odpowiednie przekonwertowanie fajnego pomysłu w wier- sze kodu. Nie wystarcza nawet wyeliminowanie wszystkich błędów poprzez wielokrotne przeczesanie kodu w poszukiwaniu usterek. Może się bowiem okazać, że aplikacja działa prawidłowo, ale zbyt wolno na sprzęcie, na jaki pozwala budżet klienta. Czasami mamy do dyspozycji jedynie mały procesor, ponieważ firma próbuje ograniczyć zużycie mocy. Czasem sukces w rywalizacji z konkurencją zależy od przepustowości lub liczby ramek na sekundę. Może się również zdarzyć, że po osiągnięciu skali niemal planetarnej firma zaczyna mieć obawy, że znacznie przyczynia się do ocieplenia globalnego. I tu pojawia się problem optymalizacji. Ta książka poświęcona jest optymalizacji, a dokładniej optymalizowaniu programów C++ ze szczególnym naciskiem na powtarzalne aspekty działania kodu C++. Niektóre z opisanych w tej książce technik odnoszą się również do innych języków programowania, ale nie było to moim celem. Inne metody optymalizacji, które działają w kodzie C++, nie przynoszą żadnych pozytywnych efektów w innych językach lub nawet nie mogą być w nich stosowane. Ta książka pokazuje, jak przekształcić poprawny kod zgodny z zaleceniami projektowy- mi języka C++ w poprawny kod, który nie tylko realizuje te zalecenia, ale dodatkowo dzia- ła szybciej i zużywa mniej zasobów na prawie każdym komputerze. Potrzeba optymalizacji często wynika z faktu, iż niektóre funkcje C++ stosowane bez zastanowienia spowalniają program i zużywają wiele zasobów. Uzyskane w ten sposób rozwiązanie, choć działa pra- widłowo, jest krótkowzroczne. Często wynika to z faktu, iż programista posiada jedynie podstawową wiedzę o nowoczesnych mikroprocesorach lub nie uwzględnił kosztu róż- nych konstrukcji C++. Inne mechanizmy optymalizacji stają się możliwe, ponieważ język C++ zapewnia ścisłą kontrolę nad różnymi aspektami zarządzania pamięcią i kopiowania. Ta książka nie opisuje, jak kodować pracochłonne procedury w assemblerze, jak zli- czać cykle bądź ile instrukcji potrafi obsługiwać równolegle najnowszy produkt firmy ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== 1 Intel. Niektórzy programiści od lat zajmują się jedną platformą (np. Xbox) i mają czas oraz potrzebę poznawać tę tajemną sztukę. Jednak zdecydowana większość programistów ma do czynienia z telefonami, tabletami lub komputerami, które mogą zawierać przeróżne mikroprocesory – także te, które nie zostały jeszcze zaprojektowane. Twórcy oprogra- mowania wbudowanego w produkty również napotykają różne procesory o odmiennej architekturze. Próba opanowania tajników tylu procesorów znacznie utrudniałaby progra- mistom podejmowanie decyzji, a w skrajnych przypadkach mogłaby nawet doprowadzić ich do obłędu. Dlatego nie zalecam tego podejścia. Optymalizacja zależna od procesora nie ma sensu w większości aplikacji, które z założenia mogą być uruchamiane na różnych procesorach. Ta książka nie wskazuje również najszybszego sposobu realizowania wybranych zadań w określonym systemie operacyjnym Windows, Linux, OS X czy systemach wbudowa- nych. Pokazuje, co można osiągnąć w języku C++, także przy użyciu standardowej biblio- teki C++. Przeprowadzanie optymalizacji w sposób wykraczający poza możliwości języka C++ utrudnia kolegom z zespołu analizowanie i komentowanie zoptymalizowanego kodu. Nie należy pochopnie podejmować takiej decyzji. Niniejsza książka uczy jak optymalizować. Próba stworzenia statycznego katalogu technik i funkcji skazana jest na porażkę, ponieważ ciągle opracowywane są nowe algo- rytmy i udostępniane nowe funkcje języka. Dlatego zdecydowałem się na przedstawienie kilku przykładów ilustrujących stopniowe udoskonalanie kodu, aby zaznajomić czytelni- ków z procesem dostosowywania kodu i wykształcić w nich umiejętność dokonywania owocnej optymalizacji. Ta książka pokazuje również, jak zoptymalizować proces programowania. Programiści świadomi kosztu wykonania opracowywanego kodu będą potrafili tworzyć kod, który od początku jest efektywny. Pisanie szybko działającego kodu zajmuje doświadczonemu programiście tyle samo czasu, ile pisanie kodu działającego powoli. Dodatkowo, ta książka uczy, jak czynić cuda – jak po wprowadzeniu zmiany uzyskać od kolegów z zespołu reakcję typu: „Zaczęło działać niesamowicie szybko. Kto coś na- prawił?”. Optymalizacja pomaga wzmocnić status programisty i zwiększyć dumę z wy- konywanego zawodu. Optymalizacja to część procesu rozwoju oprogramowania Optymalizacja jest ściśle powiązana z pisaniem kodu. W tradycyjnym procesie rozwoju oprogramowania optymalizacja następowała po zakończeniu pracy nad kodem, w fazie integracji i testowania projektu, w której można analizować wydajność całego programu. W procesie Agile można poświecić optymalizacji jeden lub dwa sprinty po napisaniu 2 | Rozdział 1: Wprowadzenie do optymalizacji ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== funkcji, która powinna spełniać pewne kryteria wydajności lub gdy konieczne jest za- pewnienie określonej wydajności. Optymalizacja ma na celu ulepszenie działania poprawnego programu tak, aby speł- niał on wymagania klientów dotyczące prędkości, przepustowości, użycia pamięci, zuży- cia energii itp. Dlatego optymalizacja zajmuje w procesie rozwoju równie ważne miejsce co pisanie funkcji. Nieakceptowalnie niska wydajność stanowi taki sam problem dla użyt- kowników jak usterki czy brakujące funkcje. Jedną z zasadniczych różnic między usuwaniem usterek a dostosowywaniem wydaj- ności jest to, że wydajność stanowi zmienną ciągłą. Funkcja albo została zaimplemen- towana, albo nie. Usterka istnieje lub nie. Natomiast wydajność może być bardzo niska, bardzo wysoka lub gdzieś pośrodku. Ponadto optymalizacja stanowi proces iteracyjny – za każdym razem, gdy usunięta zostaje najwolniejsza część programu, wyłania się nowa najwolniejsza część. Optymalizacja to w dużym stopniu sztuka eksperymentalna, która bardziej niż inne zadania programistyczne wymaga podejścia analitycznego. Aby przeprowadzać pomyślne optymalizacje, trzeba posiadać umiejętność obserwowania, formułowania testowalnych hipotez na podstawie tych obserwacji i przeprowadzania eksperymentów, które wiążą się z dokonywaniem pomiarów wspierających lub obalających postawione hipotezy. Doświadczeni programiści często uważają, że posiadają wiedzę i intuicję w zakresie two- rzenia optymalnego kodu. Jednak ci, którzy nie testują regularnie swojej intuicji, często są w błędzie. Podczas pisania programów testowych do tej książki ja także kilka razy doświadczyłem sytuacji, w której wyniki testów były niezgodne z podpowiedziami mojej intuicji. Tematem tej książki są eksperymenty, a nie przeczucia. Optymalizacja jest efektywna Programiści mają problemy z przewidzeniem, jaki wpływ na ogólną wydajność dużego programu będą miały poszczególne podejmowane przez nich decyzje. Dlatego prawie każdy gotowy program zawiera obszary, które można znacząco zoptymalizować. Nawet kod opracowany przez doświadczone zespoły dysponujące dużą ilością czasu można czę- sto przyspieszyć o 30–100 . Presja czasowa lub brak doświadczenia mogą spowodować, że wydajność może zostać podniesiona nawet 3 do 10 razy. Dostosowując kod, trudno jest uzyskać jeszcze większą poprawę wydajności. Jednak wybór lepszego algorytmu lub struktury danych może oznaczać różnicę między funkcją gotową do wdrożenia a nieak- ceptowalną ze względu na niepraktycznie wolne działanie. ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Optymalizacja jest efektywna | 3 Optymalizacja jest OK Wielu ekspertów stanowczo odradza dokonywanie optymalizacji. Zaleca, aby w ogóle z niej zrezygnować lub gdy to nieuniknione, zaczekać z nią do końca realizacji projek- tu i ograniczyć ją do minimum. Oto co słynny informatyk Donald Knuth powiedział o optymalizacji: Lepiej jest ignorować małe niewydajności przez, powiedzmy, 97 procent czasu: przedwczesna optymalizacja jest źródłem wszelkiego zła. Donald Knuth, Structured Programming with go to Statements, ACM Computing Surveys 6(4), Grudzień 1974, str. 268. CiteSeerX: 10.1.1.103.6084 (http://bit.ly/knuth-1974) A oto opinia Williama A. Wulfa: W informatyce więcej grzechów zostało popełnionych w imię efektywności (cza- sem bez jej osiągnięcia) niż z jakiegokolwiek innego powodu – łącznie z głupotą. A Case Against the GOTO. Proceedings of the 25th National ACM Conference, 1972, str. 796 Obawa przed optymalizacją rozprzestrzeniła się do tego stopnia, że czasem nawet do- świadczeni programiści wzdrygają się, gdy tylko rozmowa wkracza na temat dostosowy- wania wydajności. Moim zdaniem, opinia ta zbyt często jest cynicznie przytaczana jako usprawiedliwienie dla złych przyzwyczajeń programistycznych lub sposób uniknięcia krótkiej analizy, która mogłaby owocować uzyskaniem dużo szybszego kodu. Uważam, że bezkrytyczne akceptowanie tej porady doprowadziło do zmarnowania wielu cyklów procesora, czasu sfrustrowanych klientów i godzin pracy poświęconych na dostosowywa- nie kodu, który od początku powinien być bardziej efektywny. Moja rada jest mniej dogmatyczna. Optymalizacja jest OK. Można nauczyć się idio- mów efektywnego programowania i stosować je, nawet gdy nie ma pewności, że wydaj- ność pisanego kodu ma kluczowe znaczenie. Te idiomy reprezentują dobry kod C++ i ich stosowanie nie spotka się z dezaprobatą kolegów z zespołu. Gdy ktoś zapyta, dlaczego nie napisaliśmy czegoś „prostego” i niewydajnego, można odpowiedzieć „Napisanie wydajne- go kodu zajmuje tyle samo czasu co napisanie powolnego, marnotrawnego kodu. Dlaczego zatem miałbym celowo pisać nieefektywny kod?” Natomiast nie ma sensu godzinami analizować wyboru najlepszego algorytmu, gdy jego wydajność może mieć niewielkie znaczenie. Nie warto poświęcać tygodni na pisanie w asemblerze kodu, którego czas działania może być istotny, tylko po to, aby zniweczyć cały wysiłek poprzez wywołanie kodu jako funkcji, uniemożliwiając kompilatorowi C++ jej wcielenie. Nie jest OK żądać, aby koledzy z zespołu napisali połowę programu w C, ponieważ „wszyscy wiedzą, że język C jest szybszy”, gdy nie ma się pewności, że kod C 4 | Rozdział 1: Wprowadzenie do optymalizacji ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== rzeczywiście działa szybciej ani że kod C++ działa powoli. Innymi słowy, wszystkie za- lecenia dotyczące rozwoju programowania nadal mają zastosowanie. Optymalizacja nie usprawiedliwia łamania reguł. Nie należy marnować czasu na optymalizację, gdy nie ma się pojęcia, gdzie tkwi źródło problemów. W rozdziale 3, „Mierzenie wydajności”, wprowadzona została reguła 90/10, zgodnie z którą tylko około 10 kodu programu ma kluczowe znaczenie dla wydajności. Dlatego nie ma sensu modyfikowanie całego kodu programu w celu podniesienia jego efektywności. Ponieważ tylko 10 programu ma znaczący wpływ na wydajność, szanse przypadkowego wybrania odpowiedniego punktu wyjścia są niewielkie. W rozdziale 3 przedstawione zostały narzędzia, które pomagają w zidentyfikowaniu kluczowych miejsc w kodzie. Gdy studiowałem na uniwersytecie, profesorowie ostrzegali nas, że optymalne algoryt- my mają często wyższy koszt uruchomienia niż proste algorytmy. Dlatego należy je sto- sować tylko na dużych zbiorach danych. Chociaż reguła ta może sprawdzać się w przy- padku pewnych ezoterycznych algorytmów, moje doświadczenie wskazuje, że optymalne algorytmy realizujące proste zadania wyszukiwania i sortowania wcale nie wymagają czasochłonnych przygotowań i przynoszą korzyści także w odniesieniu do niewielkich zbiorów danych. Spotkałem się również z poradą, aby rozpocząć od zastosowania w programie naj- prostszego algorytmu i zoptymalizować go dopiero po stwierdzeniu, że program działa zbyt wolno. Ta porada pozwala na czynienie stopniowych postępów, jednak po zdobyciu pewnego doświadczenia implementowanie optymalnych operacji wyszukiwania lub sor- towania zajmuje tyle samo czasu, co implementowanie wolniejszego algorytmu. Dlatego lepiej jest od razu zrealizować zadanie porządnie, dzięki czemu wystarczy debugować jeden algorytm. Niektóre powszechnie panujące opinie są największym wrogiem procesu optymalizacji. Na przykład, „każdy wie”, że optymalny algorytm sortowania ma złożoność O(n log n), gdzie n to rozmiar zbioru danych (podrozdział „Koszt czasowy algorytmów” w rozdziale 5 zawiera krótkie wprowadzenie do notacji wielkiego O i złożoności czasowej). Powszechna opinia przynosi tę korzyść, że powstrzymuje programistów przed uznaniem sortowania przez wstawianie o złożoności O(n2) za optymalne rozwiązanie. Jednak stanowi problem, gdy zniechęca od zajrzenia do literatury i odkrycia, że szybszej działa metoda sortowania pozycyjnego o złożoności O(n logr n) (gdzie r to pozycja lub liczba kubełków) lub że sor- towanie flashsort osiąga jeszcze wyższą wydajność O(n) w przypadku losowo rozmieszczo- nych danych, lub że sortowanie szybkie, stanowiące zwykle punkt odniesienia dla pozosta- łych algorytmów, ma bardzo niską wydajność O(n2) w najgorszym przypadku. Arystoteles powiedział kiedyś, że kobiety mają mniej zębów niż mężczyźni (The History of Animals, Book II, part 1 (http://bit.ly/aristotle-animals)) i ta opinia była powszechnie akceptowana przez 1500 lat, zanim ktoś wreszcie miał w sobie tyle ciekawości, aby policzyć zęby u kilku osób. Przeciwwagą dla powszechnie panujących opinii są metody naukowe przyjmujące postać eksperymentów. W rozdziale 3 omówione zostały narzędzia do mierzenia wydaj- ności oprogramowania oraz eksperymenty sprawdzające skuteczność optymalizacji. ##7#52#aSUZPUk1BVC1WaXJ0dWFsbw== Optymalizacja jest OK | 5 W świecie informatyki krąży również opinia, że optymalizacja nie ma znaczenia. Opinia ta bazuje na przekonaniu, że nawet jeśli kod działa obecnie powoli, szybkość procesorów stale wzrasta, a zatem za jakiś czas problem sam się rozwiąże. Podobnie jak inne niesprawdzone pogłoski, to stanowisko nigdy nie było do końca słuszne. Choć mogło sprawdzać się w latach 80-tych i 90-tych, gdy na rynku panowały standardowe komputery i niezależne aplikacje, a prędkość jednordzeniowych procesorów podwajała się co 18 mie- sięcy. Natomiast obecnie wielordzeniowe procesory mają wprawdzie coraz większą moc, ale wydajność poszczególnych rdzeni wzrasta powoli, a czasem nawet maleje. Ponadto dzisiejsze programy muszą działać również na platformach mobilnych, gdzie czas baterii i dyssypacja energii ograniczają tempo wykonywania instrukcji. Co więcej, choć z czasem pojawiają się nowi klienci dysponujący szybszym sprzętem, wydajność istniejącego sprzę- tu pozostaje taka sama. A jednocześnie ilość pracy rośnie. Jedyną szansą na zwiększenie szybkości działania oprogramowania u istniejących klientów jest optymalizacja nowszych wersji. Optymalizacja chroni program przed odejściem do lamusa. Nanosekunda tu, nanosekunda tam Miliard tu, miliard tam i za chwilę mamy do czynienia z poważnymi kwotami. Cytat często błędnie przypisywany senatorowi Everettowi Dirksonowi (1898– 1969), który odrzekał się od tych słów, choć przyznał, że zdarza mu się coś chlapnąć. Komputery są niesamowicie szybkie. Potrafią wysyłać nową instrukcję szybciej niż co na- nosekundę, czyli 10-9 sekundy! W obliczu takiej prędkości łatwo jest zbagatelizować zna- czenie optymalizacji. Problem polega na tym, że im szybszy procesor, tym szybsze nawarstwianie się zbęd- nych instrukcji. Jeśli 50 instrukcji wykonywanych przez program jest niepotrzebnych, program mógłby działać dwa razy szybciej po ich usunięciu, niezależnie od tempa wyko- nywania niepotrzebnych instrukcji. Programiści twierdzący, że „wydajność nie ma znaczenia”, odnoszą się często do pew- nego typu aplikacji, podejmujących interakcję z użytkownikiem i działających na bardzo szybkich komputerach. Wydajność ma ogromne znaczenie w przypadku słabych wbudo- wanych i mobilnych procesorów z ograniczoną pamięcią, mocą lub szybkością. Jest rów- nież istotna na serwerach działających nieustannie pod dużym obciążeniem na wielkich maszynach. Innymi słowy, wydajność ma znaczenie w przypadku wszystkich aplikacji, które muszą radzić sobie z ograniczonymi zasobami (pamięcią, mocą, cyklami procesora). Wydajność ma również duże znaczenie, gdy zadanie jest na tyle du
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

C++ Optymalizacja kodu
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: