61
каждому отдельному списку опций, заняла бы меньше памяти. Это как в автомобиле:
если подсветка карты, прикуриватель и часы входят в прейскурант как единая
статья, их стоимость окажется ниже, чем если порознь выбирать каждый из
предметов. Поэтому проектировщику следует определить степень детализации опций
пользователя.
Если система проектируется для работы с памятью разного объема, возникает другой
важный вопрос. Диапазон приспособляемости нельзя сделать произвольно
широким — даже при разбиении программы на очень мелкие модули. В маленькой
системе большинство модулей перегружается. Значительная часть резидентной
памяти маленькой системы должна быть отведена для временной или страничной
памяти, в которую загружаются другие части. Ее размер ограничивает размер
каждого модуля. А разбиение функций на мелкие модули влечет потери и
производительность, и памяти. Поэтому в большой системе, где временная память в
двадцать раз больше, она лишь позволяет уменьшить количество обращений. Из-за
маленьких размеров модулей система все-таки теряет в скорости и расходовании
памяти. По этой причине эффективность системы, которую можно построить их
модулей маленькой системы, ограничена.
Второй областью приложения мастерства является нахождение компромисса между
памятью и быстродействием. Для отдельной функции увеличение памяти влечет за
собой рост быстродействия, что справедливо в удивительно широком диапазоне
величин. Этот факт делает возможным установление ресурсов памяти.
Чтобы облегчить своей команде поиск правильного соотношения между памятью и
производительностью, менеджер может сделать две вещи. Во-первых, организовать
обучение технике программирования, а не просто полагаться на природный ум и
предшествующий опыт. Это особенно важно, если машина или язык новые.
Особенности их эффективного использования нужно быстро изучить и сделать
общим достоянием, возможно, присуждая особые призы за освоение новой техники.
Во-вторых, нужно понять, что у программирования есть технология и компоненты
нужно собирать из готовых частей. В каждом проекте должен иметься набор
хороших процедур или макросов для обработки очередей, поиска, хеширования и
сортировки, причем не менее чем в двух вариантах: одном быстром, другом
экономящем память. Разработка такой технологии является важной задачей
реализации, которую можно решать параллельно с разработкой системной
архитектуры.
Представление — суть программирования
За мастерством стоит изобретательность, благодаря которой появляются
экономичные и быстрые программы. Почти всегда это является результатом
стратегического прорыва, а не тактического умения. Иногда таким стратегическим
прорывом является алгоритм, как, например, быстрое преобразование Фурье,
предложенное Кули и Тьюки, или замена n
2
сравнений на n log n при сортировке.
Гораздо чаще стратегический прорыв происходит в результате представления
данных или таблиц. Здесь заключена сердцевина программы. Покажите мне блок-
схемы, не показывая таблиц, и я останусь в заблуждении. Покажите мне ваши
таблицы, и блок-схемы, скорей всего, не понадобятся: они будут очевидны.
Примеры мощи, которой обладает представление, легко умножить. Я вспоминаю
одного молодого человека, занимавшегося созданием усовершенствованного
консольного интерпретатора для IBM 650. Ему удалось вместить его в поразительно
малое пространство благодаря разработке интерпретатора для интерпретатора и
пониманию того, что взаимодействие человека с машиной происходит медленно и
редко, а память дорога. Элегантный маленький компилятор с Fortran фирмы Digitek
использует особое очень плотное представление кода самого компилятора,
благодаря чему не требуется внешней памяти. Время, которое тратится на
распаковку кода, десятикратно окупается за счет отсутствия ввода-вывода.
(Упражнения в конце главы 6 книги Брукса и Иверсона «Автоматическая обработка
данных»
1
включает подборку таких примеров, как и многие упражнения у Кнута.
2
)