Искусство программирования для Unix
Шрифт:
Описанная стратегия является распространенной не только в области сетевых протоколов. Когда требуется сократить задержку, блокировка или ожидание немедленных результатов — крайне неэффективные методы.
12.4.3. Кэширование результатов операций
Иногда можно получить оба преимущества (низкую задержку и хорошую пропускную способность) путем вычисления дорогостоящих результатов по мере необходимости и их кэширования для последующего использования. Выше было сказано, что в службе named задержка сокращается путем пакетирования. Кроме
Кэширование имеет собственные проблемы и компромиссные решения, которые хорошо иллюстрируются одним примером: использование двоичного кэша для устранения издержек синтаксического анализа, связанного с файлами текстовых баз данных. В некоторых вариантах операционной системы Unix данная методика использовалась для ускорения доступа к парольной информации (обычным обоснованием было сокращение задержки при регистрации в системе на очень крупных узлах).
Для того чтобы обеспечить соответствующую отдачу от использования данной методики, необходимо чтобы весь код, обращающийся к бинарному кэшу, проверял временные метки на обоих файлах и обновлял кэш в случае, если мастер-текст имеет более позднюю метку. С другой стороны, все изменения мастер-текста должны выполнятся посредством упаковщика, который обновляет двоичный формат.
Несмотря на то, что данный подход оказывается работоспособным, он обладает всеми недостатками, которые можно ожидать при нарушении правила SPOT. Дублирование данных означает, что в результате не будет никакой экономии пространства, т.е. это исключительно оптимизация скорости. Однако реальная проблема данного подхода заключается в том, что код для обеспечения когерентности между кэшем и мастер-текстом печально известен как "текучий" и чреватый ошибками. Очень частое обновление файлов кэша может привести к неочевидной конкуренции просто ввиду односекундного разрешения временных меток.
Но когерентность все-таки можно гарантировать в простых случаях. Одним из них является интерпретатор языка Python, который компилирует и сохраняет на диске файл p-кода с расширением
Однако, когда модель обновления главных файлов более сложна, код обеспечения синхронизации склонен к утечкам. Unix-варианты, использующие данную методику для ускорения доступа к критически важным системным базам данных, имели дурную репутацию среди системных администраторов.
Как правило, файлы бинарного кэша являются хрупкой методикой, и, вероятно, будет лучше избегать их использования. Усилия, затраченные на реализацию специализированных средств для сокращения задержки, в данном случае было бы целесообразнее направить на совершенствование конструкции приложения, так чтобы в ней не было "бутылочного горлышка", или даже на тонкую настройку для повышения скорости файловой системы или реализации
Если ситуация на первый взгляд требует использования методики кэширования, то разумно будет взглянуть на уровень глубже и ответить на вопрос: почему вообще понадобилось кэширование? Решение данной проблемы вполне может оказаться не сложнее, чем правильное решение всех граничных случаев в кэширующем программном обеспечении.
13
Сложность: просто, как только возможно, но не проще
Все следует делать так просто, как только возможно, но не проще.
В конце главы 1 философия Unix была сведена к общему принципу — K.I.S.S. (Keep It Simple, Stupid! Будь проще!). В части "Проектирование" данной книги одной из ключевых тем была важность сохранения максимально возможной простоты конструкции и реализации. Однако, что значит "просто, как только возможно"?
Рассмотрение данного вопроса откладывалось до настоящей главы потому, что простота — комплексное понятие. В качестве теоретической основы при изучении данной темы необходимы некоторые идеи, которые были сформулированы ранее в части "Проектирование", особенно в главах 4 и 11.
Важными вопросами в данной главе являются основные предубеждения Unix-традиции. Некоторые из этих предубеждений стали причинами идеологических войн, продолжавшихся в течение десятилетий. Данная глава начинается с рассмотрения установившейся практики и терминологии Unix, а затем несколько выходит за рамки этой тематики. Автор не пытается сформулировать здесь простые ответы на данные вопросы, это невозможно, однако концептуальные средства, описанные в настоящей главе, вероятно, позволят читателям продвинуться дальше в собственном поиске ответов.
13.1. Сложность
Как и в случае рассмотренных выше вопросов модульности и проектирования интерфейсов, Unix-программисты воспринимают ряд отличий, которые они часто усваивают из опыта, даже не зная, как их назвать. Поэтому начинать следует с изложения некоторых терминов.
Раздел начинается с определения того, в чем заключается сложность программного обеспечения. Далее определяются некоторые горизонтальные границы между несколькими разновидностями сложности. Завершается данный раздел определением еще более важных вертикальных различий между видами сложности, с которыми приходится смириться, и видами сложности, которые можно устранить.
13.1.1. Три источника сложности
Вопросы о простоте, сложности и верном размере программного обеспечения вызывают бурные споры в Unix-сообществе. Unix-программисты развили такое мировоззрение, согласно которому простота — это красота, изящество и добро, а сложность — уродство, абсурдность и зло
В основе программистского стремления отстаивать простоту лежит прагматичный факт: сложность дорого обходится. Сложное программное обеспечение труднее анализировать, тестировать, отлаживать, сопровождать, но прежде всего его сложнее изучать и использовать. Издержки сложности, не устраненные во время разработки, резко проявляются после внедрения программы. Сложность создает источники ошибок, из которых они распространяются и создают проблемы на протяжении всего срока службы программного обеспечения.