- •Оглавление
- •Об авторе
- •Благодарности
- •Предисловие
- •Глава 1. Держим оборону
- •На пути к хорошему коду
- •Готовьтесь к худшему
- •Что такое защитное программирование?
- •Этот страшный, ужасный мир
- •Технологии защитного программирования
- •Выберите хороший стиль кодирования и пользуйтесь крепкой архитектурой
- •Пишите код без спешки
- •Не верьте никому
- •Стремитесь к ясности, а не к краткости
- •Не позволяйте никому лезть туда, где ему нечего делать
- •Включайте вывод всех предупреждений при компиляции
- •Пользуйтесь средствами статического анализа
- •Применяйте безопасные структуры данных
- •Проверяйте все возвращаемые значения
- •Аккуратно обращайтесь с памятью (и другими ценными ресурсами)
- •Инициализируйте все переменные там, где вы их объявили
- •Объявляйте переменные как можно позже
- •Пользуйтесь стандартными средствами языка
- •Пользуйтесь хорошими средствами регистрации диагностических сообщений
- •Выполняйте приведение типов с осторожностью
- •Подробности
- •Ограничения
- •Какие ограничения налагать
- •Снятие ограничений
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 2. Тонкий расчет
- •Да в чем проблема?
- •Знайте своих клиентов
- •Что такое хорошее представление?
- •Размещение скобок
- •Скобки в стиле K&R
- •Расширенный стиль скобок
- •Стиль Уайтсмита (с отступами)
- •Другие стили скобок
- •Единственно верный стиль
- •Внутрифирменные стили (и когда их придерживаться)
- •Установка стандарта
- •Религиозные войны?
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 3. Что в имени тебе моем?
- •Зачем нужны хорошие имена?
- •Каким объектам мы даем имена?
- •Игра в названия
- •Описательность
- •Техническая корректность
- •Идиоматичность
- •Тактичность
- •Технические подробности
- •Имена переменных
- •Имена функций
- •Имена типов
- •Пространства имен
- •Имена макросов
- •Имена файлов
- •Роза пахнет розой
- •Соблюдайте единообразие
- •Связывайте имя с содержимым
- •Извлекайте выгоду из выбора имени
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 4. Литературоведение
- •Самодокументируемый код
- •Техника написания самодокументируемого кода
- •Пишите простой код с хорошим форматированием
- •Выбирайте осмысленные имена
- •Разбивайте код на самостоятельные функции
- •Выбирайте содержательные имена типов
- •Применяйте именованные константы
- •Выделяйте важные фрагменты кода
- •Объединяйте взаимосвязанные данные
- •Снабжайте файлы заголовками
- •Правильно обрабатывайте ошибки
- •Пишите осмысленные комментарии
- •Практические методологии самодокументирования
- •Грамотное программирование
- •Инструментарий документирования
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 5. Заметки на полях
- •Что есть комментарий в коде?
- •Как выглядят комментарии?
- •Сколько комментариев требуется?
- •Что помещать в комментарии?
- •Не нужно описывать код
- •Не подменяйте код
- •Как сделать комментарии полезными
- •Не отвлекаться
- •На практике
- •Замечание об эстетичности
- •Единообразие
- •Четкие блочные комментарии
- •Отступы в комментариях
- •Комментарии в конце строки
- •Помощь в чтении кода
- •Стиль должен обеспечивать легкость сопровождения
- •Границы
- •Флажки
- •Комментарии в заголовке файла
- •Работа с комментариями
- •Помощь при написании программ
- •Заметки об исправлении ошибок
- •Устаревание комментариев
- •Сопровождение и бессодержательные комментарии
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 6. Людям свойственно ошибаться
- •Откуда что берется
- •Механизмы сообщения об ошибках
- •Без обработки ошибок
- •Возвращаемые значения
- •Переменные, содержащие состояние ошибки
- •Исключения
- •Сигналы
- •Обнаружение ошибок
- •Обработка ошибок
- •Когда обрабатывать ошибки
- •Варианты реагирования
- •Последствия для кода
- •Подымаем скандал
- •Управление ошибками
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 7. Инструментарий программиста
- •Что такое инструмент программирования?
- •А зачем они нужны – инструменты?
- •Электроинструменты
- •Выясните, каковы его возможности
- •Научитесь им управлять
- •Выясните, для каких задач он пригоден
- •Убедитесь, что он работает
- •Имейте четкие данные о том, как получить дополнительные сведения
- •Узнайте, как получить новые версии
- •Какой инструмент необходим?
- •Средства редактирования исходного кода
- •Средства построения кода
- •Инструменты для отладки и тестирования
- •Средства поддержки языка
- •Инструменты различного назначения
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 8. Время испытаний
- •Проверка на подлинность
- •Кто, что, когда, зачем?
- •Зачем тестировать
- •Кому тестировать
- •В чем состоит тестирование
- •Когда тестировать
- •Типы тестирования
- •Выбор контрольных примеров для блочного тестирования
- •Архитектура и тестирование
- •Руками не трогать!
- •Анатомия провала
- •Справлюсь ли я сам?
- •Система контроля ошибок
- •Обсуждение ошибок
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 9. Поиск ошибок
- •Реальные факты
- •Природа этого зверя
- •Взгляд с высоты птичьего полета
- •Взгляд с поверхности земли
- •Взгляд из глубины
- •Борьба с вредителями
- •Обходная дорога
- •Правильный путь
- •Охота за ошибками
- •Ошибки этапа компиляции
- •Ошибки этапа исполнения
- •Как исправлять ошибки
- •Профилактика
- •Отладчик
- •Средство проверки доступа к памяти
- •Трассировщик системных вызовов
- •Дамп памяти
- •Журналирование
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 10. Код, который построил Джек
- •Языковые барьеры
- •Интерпретируемые языки
- •Компилируемые языки
- •Делаем слона из мухи
- •Выполнение сборки
- •Что должна уметь хорошая система сборки?
- •Простота
- •Единообразие
- •Повторяемость и надежность
- •Атомарность
- •Борьба с ошибками
- •Механика сборки
- •Выбор целей
- •Уборка
- •Зависимости
- •Автоматическая сборка
- •Конфигурация сборки
- •Рекурсивное применение make
- •Мастер на все руки
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 11. Жажда скорости
- •Что такое оптимизация?
- •От чего страдает оптимальность кода?
- •Доводы против оптимизации
- •Альтернативы
- •Нужна ли оптимизация
- •Технические подробности
- •Убедитесь, что нужна оптимизация
- •Определите самую медленную часть кода
- •Тестирование кода
- •Оптимизация кода
- •После оптимизации
- •Методы оптимизации
- •Конструктивные изменения
- •Модификация кода
- •Как писать эффективный код
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 12. Комплекс незащищенности
- •Риски
- •Наши оппоненты
- •Оправдания, оправдания
- •Ощущение незащищенности
- •Опасный проект и архитектура
- •Переполнение буфера
- •Встроенные строки запросов
- •Условия гонки
- •Целочисленное переполнение
- •Дела защитные
- •Технология установки системы
- •Технология конструирования программного обеспечения
- •Технологии реализации кода
- •Технологии процедуры
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 13. Важность проектирования
- •Программирование как конструкторская работа
- •Что нужно проектировать?
- •Хороший проект программного продукта
- •Простота
- •Элегантность
- •Модульность
- •Хорошие интерфейсы
- •Расширяемость
- •Избегайте дублирования
- •Переносимость
- •Идиоматичность
- •Документированность
- •Как проектировать код
- •Методы и процедуры проектирования
- •Инструменты проектирования
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 14. Программная архитектура
- •Что такое программная архитектура?
- •План программы
- •Точки зрения
- •Где и когда этим заниматься?
- •Для чего она применяется?
- •Компоненты и соединения
- •Какими качествами должна обладать архитектура?
- •Архитектурные стили
- •Без архитектуры
- •Многоуровневая архитектура
- •Архитектура с каналами и фильтрами
- •Архитектура клиент/сервер
- •Компонентная архитектура
- •Каркасы
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 15. Программное обеспечение – эволюция или революция?
- •Гниение программного обеспечения
- •Тревожные симптомы
- •Как развивается код?
- •Вера в невозможное
- •Как с этим бороться?
- •Как писать новый код
- •Сопровождение существующего кода
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 16. Кодеры
- •Мартышкин труд
- •Нетерпеливый
- •Кодер (Code Monkey)
- •Гуру
- •Псевдогуру
- •Высокомерный гений
- •Ковбой
- •Плановик
- •Ветеран
- •Фанатик
- •Монокультурный программист
- •Лодырь
- •Руководитель поневоле
- •Идеальный программист
- •И что из этого следует?
- •Для глупцов
- •Резюме
- •План действий
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 17. Вместе мы – сила
- •Команды – общий взгляд
- •Организация команды
- •Методы управления
- •Разделение ответственности
- •Организация и структура кода
- •Инструменты для групповой работы
- •Болезни, которым подвержены команды
- •Вавилонская башня
- •Диктатура
- •Демократия
- •Большой Каньон
- •Зыбучие пески
- •Лемминги
- •Личное мастерство и качества, необходимые для работы в команде
- •Общение
- •Скромность
- •Разрешение конфликтов
- •Обучение и приспособляемость
- •Знание пределов своих возможностей
- •Принципы групповой работы
- •Коллективное владение кодом
- •Нормы кодирования
- •Определите, что считать успехом
- •Установите ответственность
- •Избегайте истощения
- •Жизненный цикл команды
- •Создание команды
- •Рост команды
- •Групповая работа
- •Роспуск команды
- •Резюме
- •План действий
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 18. Защита исходного кода
- •Управление версиями исходного кода
- •Контроль версий
- •Контроль доступа
- •Работа с хранилищем
- •Пусть растут деревья
- •Краткая история систем контроля за исходным кодом
- •Управление конфигурацией
- •Резервное копирование
- •Выпуск исходного кода
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 19. Спецификации
- •Что же это такое, конкретно?
- •Типы спецификаций
- •Спецификация требований
- •Функциональная спецификация
- •Спецификация системной архитектуры
- •Спецификация интерфейса пользователя
- •Проектная спецификация
- •Спецификация тестирования
- •Что должны содержать спецификации?
- •Процесс составления спецификаций
- •Почему мы не пишем спецификации?
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Когда проводить рецензирование?
- •Нужно ли рецензировать
- •Какой код рецензировать
- •Проведение рецензирования кода
- •Рецензирование на собраниях
- •Интеграционное рецензирование
- •Пересмотрите свое отношение
- •Позиция автора
- •Позиция рецензента
- •Идеальный код
- •За пределами рецензирования кода
- •Резюме
- •Контрольный список
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 21. Какой длины веревочка?
- •Выстрел в темноте
- •Почему трудно делать оценки?
- •Под давлением
- •Практические способы оценки
- •Игры с планами
- •Не отставай!
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 22. Рецепт программы
- •Стили программирования
- •Структурное программирование
- •Функциональное программирование
- •Логическое программирование
- •Рецепты: как и что
- •Процессы разработки
- •Каскадная модель
- •SSADM и PRINCE
- •Создание прототипов
- •Итеративная и инкрементная разработка
- •Спиральная модель
- •Другие процессы разработки
- •Спасибо, хватит!
- •Выбор процесса
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 23. За гранью возможного
- •Программирование приложений
- •Коробочные продукты
- •Заказные приложения
- •Программирование игр
- •Системное программирование
- •Встроенное программное обеспечение
- •Программирование масштаба предприятия
- •Численное программирование
- •И что дальше?
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 24. Что дальше?
- •Но что же дальше?
- •Ответы и обсуждение
- •Глава 1. Держим оборону
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 2. Тонкий расчет
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 3. Что в имени тебе моем?
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 4. Литературоведение
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 5. Заметки на полях
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 6. Людям свойственно ошибаться
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 7. Инструментарий программиста
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 8. Время испытаний
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 9. Поиск ошибок
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 10. Код, который построил Джек
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 11. Жажда скорости
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 12. Комплекс незащищенности
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 13. Важность проектирования
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 14. Программная архитектура
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 15. Программное обеспечение – эволюция или революция?
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 16. Кодеры
- •Вопросы для размышления
- •Глава 17. Вместе мы – сила
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 18. Защита исходного кода
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 19. Спецификации
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 20. Рецензия на отстрел
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 21. Какой длины веревочка?
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 22. Рецепт программы
- •Вопросы для размышления
- •Глава 23. За гранью возможного
- •Вопросы для размышления
- •Вопросы личного характера
- •Библиография
- •Алфавитный указатель
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
|
|
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
w Click |
|
|
|
Методыm |
оптимизации |
|||||
|
|
|
|
|||||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
279Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Вот несколько очень важных советов, касающихся проведения заме% ров времени:
•Используйте одни и те же входные данные в тестах, проводимых до и после оптимизации. В противном случае ваши тесты окажутся бессмысленными; вы будете сравнивать хрен с апельсином. Лучше всего воспользоваться автоматизированным контрольным приме% ром (см. «Руками не трогать!» на стр. 203) – с такого же рода реаль% ными репрезентативными данными, как при профилировании.
•Выполняйте тесты в обычных одинаковых условиях, чтобы исклю% чить влияние на результат таких факторов, как загрузка ЦП или объем свободной памяти.
•Ваши тесты не должны зависеть от того, насколько быстро пользо% ватели вводят данные, поскольку скорость работы пользователей может меняться в широком диапазоне. Постарайтесь автоматизи% ровать все, что только удастся.
Оптимизация кода
Ниже будут рассмотрены некоторые конкретные приемы оптимизации. Ускорение может быть достигнуто в результате как простой переработ% ки небольшого раздела кода, так и серьезных изменений на уровне про% екта. Задача в том, чтобы оптимизировать код, не поломав его при этом.
Определите, какие способы существуют для оптимизации данного ко% да, и выберите из них лучший. Вносите изменения по одному; это ме% нее рискованно и позволяет определить, от чего в большей степени за% висит производительность. Иногда наибольший эффект оптимизации дают совершенно неожиданные факторы.
После оптимизации
Не забудьте провести тестирование оптимизированного кода, чтобы убедиться в успешности сделанных модификаций. Если оптимизация не удалась, отмените сделанные изменения. Тут вам поможет система управления версиями, с помощью которой вы вернетесь к предыдуще% му варианту кода.
Отмените также те изменения, которые незначительно оптимизиро% вали код. Лучше иметь ясный код, чем скромные результаты оптими% зации (если, конечно, у вас нет абсолютной необходимости ускорить код и отсутствуют другие способы сделать это).
Методы оптимизации
Мы долго обсуждали общие вопросы; пора заняться конкретными де% талями. Следуя описанной выше процедуре оптимизации, вы убеди% лись, что программа работает неэффективно, и нашли код, больше все% го повинный в этом. Необходимо переделать его. Что для этого нужно?
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
C |
|
E |
|
|||
|
|
X |
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
||
|
F |
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
r |
|
P |
|
|
|
|
|
NOW! |
o |
||
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|||
|
|
|
|
to |
|
|
|
|
|
w Click |
|
|
|
280m |
|||||
|
|
|
|
||||||
w |
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
. |
|
|
|
|
|
.c |
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
df |
|
|
n |
e |
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
Глава 11. Жажда скоростиClick |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Существуют различные виды оптимизации. Какой из них подойдет в вашем случае, зависит от конкретной проблемы, вашей цели (напри% мер, увеличить скорость или уменьшить размер кода) и требуемой сте% пени оптимизации.
Можно выделить две категории оптимизаций: изменение проекта и изменение кода. Изменения на уровне проекта обычно оказывают бо% лее значительный эффект на производительность, чем модификации на уровне кода. Неудачный проект может гораздо больше снизить эффек% тивность, чем несколько неудачных строк исходного кода, поэтому кон% структивные изменения, хотя и более трудные, дают большую отдачу.
Чаще всего возникает задача повысить скорость выполнения. Для по% вышения скорости предлагаются следующие пути:
•Заменить медленный код быстрым
•Реже обращаться к медленному коду
•Откладывать выполнение медленного кода до того момента, когда оно реально потребуется
Другие распространенные задачи оптимизации – уменьшение требуе% мой памяти (в основном путем изменения представления данных, мо% дификации схемы работы с памятью или сокращения объема данных, одновременно находящихся в памяти) или уменьшение размера вы% полняемого модуля (путем сокращения функциональности или удале% ния повторяющегося кода). Как будет продемонстрировано, эти зада% чи часто противоречат одна другой: рост скорости часто происходит за счет увеличения потребления памяти, и наоборот.
Конструктивные изменения
Имеются в виду макрооптимизации – крупные изменения, направ% ленные на улучшение внутренней конструкции вашего программного продукта. Исправлять плохой проект тяжело. Чем ближе срок завер% шения проекта, тем менее вероятно, что вы станете вносить конструк% тивные изменения; это слишком рискованно.1 В итоге мы ограничива% емся заделкой обнаружившихся трещин, делая небольшие заплатки на уровне кода.
Если отважиться на конструктивные изменения, то для оптимизации можно прибегнуть к следующему:
•Ввести дополнительное кэширование или буферизацию, чтобы ус% корить доступ к данным или избежать длительных повторяющихся вычислений. Можно заранее вычислить величины, которые вам по% требуются, и запомнить их, чтобы иметь к ним мгновенный доступ.
•Создать пул ресурсов для сокращения расходов на выделение памя% ти объектам. Например, можно заранее выделить память или дер%
1Увы, обычно обращают внимание на то, что эффективность программы не%
достаточна, лишь тогда, когда завершение проекта уже на носу.
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
|
|
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
w Click |
|
|
|
Методыm |
оптимизации |
|||||
|
|
|
|
|||||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
281Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
жать открытыми файлы, вместо того чтобы многократно открывать и закрывать их. Такой прием часто используется для ускорения вы% деления памяти; процедуры выделения памяти старых ОС проекти% ровались для применения в простом однопоточном режиме. Их бло% кировки очень сильно тормозят многопоточные приложения.
•Пожертвовать точностью ради скорости, если это допустимо. На% пример, отказаться от вычислений с числами с плавающей точкой. В некоторых устройствах отсутствует блок для вычислений с плава# ющей точкой (FPU) и применяется их программная эмуляция, ко% торая медленна. Можно выбрать библиотеки арифметики с фикси% рованной точкой, чтобы избежать эмуляции, но потерять при этом точность вычислений. Особенно просто это делается в C++ с помо% щью абстрактных типов данных.
Точность связана не только с типами данных; эту тактику можно развить гораздо глубже, выбирая те или иные алгоритмы или каче% ство представления результирующих данных. Можно также оста% вить решение на усмотрение пользователя – выбрать режим мед# ленной, но точной работы или быстрой, но приближенной.
•Изменить формат хранения данных или их представления на дис% ке, сделав его более подходящим для скоростной обработки. Напри% мер, ускорить синтаксический анализ текстового файла, воспользо% вавшись двоичным форматом. Передавать или хранить файлы в сжатом виде, чтобы повысить эффективность их передачи по сети.
•Применить распараллеливание задач и многопоточность, чтобы од% но действие не ждало окончания выполнения другого. По мере того как иссякают возможности роста скорости процессоров, их произво% дители все чаще выпускают процессоры с несколькими ядрами и не% сколькими конвейерами. Чтобы воспользоваться их преимущества% ми, ваш код должен быть спроектирован с учетом многопоточной модели. Борьба за оптимизацию активно осваивает это направление.
•Эффективно организовать потоки: избегать или удалять лишние блокировки. Они препятствуют параллельному выполнению, тре% буют дополнительных накладных расходов и часто приводят к вза% имным блокировкам. С помощью статического анализа проверьте, какие блокировки вам необходимы, а какие нет.
•Не злоупотреблять исключениями (exceptions). Они могут поме% шать компилятору выполнить оптимизацию1 и нанести ущерб бы% стродействию, если применяются слишком часто.
•Отказаться от определенных средств языка, если это поможет сократить объем кода. Некоторые компиляторы C++ позволяют
1Как и функции, блоки try/catch представляют собой препятствие для опти% мизатора. Через них не видно, есть ли возможность оптимизации, поэтому
некоторые приемы ускорения могут оказаться не реализованными.
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
C |
|
E |
|
|||
|
|
X |
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
||
|
F |
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
r |
|
P |
|
|
|
|
|
NOW! |
o |
||
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|||
|
|
|
|
to |
|
|
|
|
|
w Click |
|
|
|
282m |
|||||
|
|
|
|
||||||
w |
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
. |
|
|
|
|
|
.c |
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
df |
|
|
n |
e |
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
Глава 11. Жажда скоростиClick |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
отключить RTTI и исключительные ситуации, тем самым умень% шив размер исполняемого модуля.
•Ограничить функциональность: самый быстрый код тот, который во% обще не выполняется. Функция будет работать медленно, если она делает много вещей, которые не нужны. Уберите все лишнее. Перене% сите его в какое%нибудь другое место. Откладывайте выполнение вся% кой работы до того времени, когда она действительно понадобится.
•Пожертвовать качеством конструкции ради скорости. Например, сократить косвенность и увеличить связывание. Для этого можно нарушить правила инкапсуляции: предоставить открытый интер% фейс для закрытой реализации класса. Разрушая границы между модулями, вы наносите непоправимый ущерб всему проекту. По возможности попытайтесь сначала прибегнуть к менее разруши% тельным средствам.
Обозначения для сложности
Алгоритмическая сложность – это мера того, насколько хорошо масштабируется алгоритм: какова зависимость времени его вы% полнения от объема входных данных. Это качественная матема% тическая модель, позволяющая быстро сравнить эффективность различных способов реализации. Она не показывает конкретное время выполнения (оно сильно зависит от скорости ЦП, настро% ек ОС и т. д.).
Сложность определяется как объем работы, которую должен осу% ществить алгоритм: количество выполненных элементарных операций. Элементарными операциями считаются арифметиче% ские действия, присваивание, проверка, чтение/запись данных и т. п. Алгоритмическая сложность не показывает, сколько именно операций должно быть выполнено, а отражает связь этой величины с размерностью задачи. Обычно нас интересует поведе% ние алгоритма в худшем случае, т. е. самый большой объем рабо% ты, который ему может потребоваться проделать. Для сравнения неплохо также знать сложность в лучшем случае и в среднем.
Алгоритмическая сложность обозначается с помощью «О боль% шого» – системы, придуманной немецким специалистом по тео% рии чисел Эдмундом Ландау. Задача с размером входных дан% ных n может иметь сложность:
O(1): порядка 1
Это алгоритм с постоянным временем. Каков бы ни был объ% ем входных данных, выполнение задачи всегда требует одно% го и того же времени. Это лучший показатель эффективности из всех возможных.
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
|
|
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
w Click |
|
|
|
Методыm |
оптимизации |
|||||
|
|
|
|
|||||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
283Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
O(n): порядка n
Сложность алгоритма с линейным временем пропорциональна размеру входных данных. Поиск в связанном списке требует обхода все большего количества узлов по мере роста списка; количество операций прямо пропорционально длине списка.
O(n2): порядка n в квадрате
В этом случае дело с производительностью гораздо хуже: сложность растет быстрее, чем объем входных данных. Алго% ритм с квадратичным временем может быть совсем не плох, когда объем входных данных для него невелик, но для боль% ших наборов данных он может выполняться очень долго. Ал% горитм пузырьковой сортировки имеет сложность O(n2).
Порядок сложности может быть любым; например, алгоритм быстрой сортировки имеет сложность O(n log n), что хуже, чем O(n), но гораздо лучше, чем O(n2). Простой способ оптимизации медленного алгоритма пузырьковой сортировки – это замена его алгоритмом быстрой сортировки, тем более что множество его реализаций находится в свободном доступе.
Обозначения в виде «О большого» не содержат констант или чле% нов более низкого порядка. Вы едва ли встретите сложность типа O(2n+6). Когда n достаточно велико, эти константы и члены более низкого порядка становятся несущественны.
Основные оптимизации уровня проекта включают в себя усовершенст% вование алгоритмов или структур данных. В большинстве случаев неудовлетворительная скорость или чрезмерный расход памяти обу% словлены недостатками одного или обоих из указанных факторов, над которыми и следует работать.
Алгоритмы
Алгоритмы оказывают огромное влияние на скорость выполнения программы. Функция, которая удовлетворительно работает в не% большом локальном тесте, может не справиться с реальными дан% ными. Если профилирование показывает, что ваш код значитель% ную часть времени проводит в некоторой функции, нужно заста% вить ее работать быстрее. Можно работать с ней на уровне кода, вы% жимая все, что можно, из каждой команды. Но лучше заменить весь алгоритм, найдя более эффективный его вариант.
Рассмотрим конкретный пример. Пусть некоторый алгоритм вы% полняет цикл 1000 раз. Каждый проход тела цикла занимает 5 мил% лисекунд. Вся операция, таким образом, длится около 5 секунд. До% пустим, модифицировав код внутри цикла, вы сократите каждую итерацию на 1 мс; это даст вам выигрыш в 1 секунду. Неплохо.