7. Кодирование с учетом масштабируемости
Всегда помните о возможном росте данных. Подумайте об асимптотической сложности без преждевременной оптимизации. Алгоритмы, которые работают с пользовательскими данными, должны иметь предсказуемое и, желательно, не хуже, чем линейно зависящее от количества обрабатываемых данных время работы. Когда становится важной и необходимой оптимизация, в особенности из-за роста объемов данных, в первую очередь следует улучшать
Эта рекомендация иллюстрирует важную точку равновесия между рекомендациями 8 и 9 — не оптимизируйте преждевременно и не пессимизируйте преждевременно. Это делает данный материал трудным в написании, поскольку он может быть неверно истолкован как совет о 'преждевременной оптимизации'. Это не так.
Вот предпосылки для данной рекомендации. Память и дисковая емкость растут экспоненциально; например, с 1988 по 2004 год емкость дисков росла примерно на 112% в год (почти в 1900 раз за десятилетие). Очевидным следствием этого факта является то, что любой ваш сегодняшний код завтра может иметь дело с большими объемами данных —
Защита против такого будущего означает, что мы должны избежать встраивания в наши программы того, что станет западней при работе с большими файлами, большими базами данных, с большим количеством пикселей, большим количеством окон, процессов, битов, пересылаемых по каналам связи. Одним из важных факторов успеха такой защиты является то, что стандартная библиотека С++ обеспечивает гарантированную сложность операций и алгоритмов над контейнерами STL.
Здесь и надо искать точку равновесия. Очевидно, что неверно прибегать к преждевременной оптимизации путем использования менее понятных алгоритмов в ожидании больших объемов данных, которые могут никогда не материализоваться. Не менее очевидно и то, что неверно прибегать и к преждевременной пессимизации, закрывая глаза на сложность алгоритмов (О-сложность), а именно — стоимость вычислений как функцию от количества элементов данных, с которыми работает алгоритм.
Данный совет состоит из двух частей. Во-первых, даже до того, как станет известно, будут ли объемы данных достаточно велики, чтобы для конкретных вычислений возникла проблема, по умолчанию следует избегать использования алгоритмов, которые работают с пользовательскими данными (которые могут расти), но не способны к масштабированию, если только использование менее масштабируемого алгоритма не приводит к существенному повышению понятности и удобочитаемости кода (см. рекомендацию 6). Но все мы часто сталкиваемся с сюрпризами. Мы пишем десять фрагментов кода, думая, что они никогда не будут иметь дела с большими наборами данных. И это действительно оказывается так — в девяти случаях из десяти. В десятом случае мы сталкиваемся с проблемами производительности. Это не раз случалось с нами, и мы знаем, что это случалось (или случится) и с вами. Конечно, мы вносили исправления и передавали их потребителям, но лучше было бы избежать таких затруднений и выполнения лишней работы. Так что при прочих равных условиях (включая понятность и удобочитаемость) воспользуйтесь следующими советами.
•
•
• push_back
или поиск в хэш- таблице (см. рекомендации 76 и 80). Неплохи алгоритмы со сложностью set
/map
и lower_bound
или upper_bound
с итераторами произвольного доступа (см. рекомендации 76, 85 и 86). Допустима линейная сложность Ovector::insert
или for_each
(см. рекомендации 76, 81 и 84).
•
•
Во-вторых, после того как замеры покажут, что оптимизация действительно нужна и важна, в особенности при росте данных, сконцентрируйте усилия на снижении
Итак, предпочтительно использовать линейные (или лучшие) алгоритмы там, где только это возможно. Избегайте, где можете, алгоритмов с более чем линейной сложностью, и уж тем более — экспоненциальных.
8. Не оптимизируйте преждевременно
Как гласит пословица, не подгоняйте скачущую лошадь. Преждевременная оптимизация непродуктивна и быстро входит в привычку. Первое правило оптимизации: не оптимизируйте. Второе правило оптимизации (только для экспертов): не оптимизируйте ни в коем случае. Семь раз отмерь, один раз оптимизируй.
В [Stroustrup00] §6 имеется замечательная цитата:
Преждевременная оптимизация — корень всех бед.
С другой стороны, мы не можем игнорировать эффективность.