Искусство программирования для Unix - Реймонд Эрик Стивен
Шрифт:
Интервал:
Закладка:
Даже если текстовые потоки были бы менее эффективными, чем RPC, потери производительности были бы незначительными и линейными, а такую проблему лучше решать с помощью модернизации аппаратного обеспечения, чем путем увеличения времени разработки или внесения дополнительной архитектурной сложности. Все потери производительности при использовании текстовых потоков, компенсируются благодаря возможности разрабатывать менее сложные системы, которые упрощают мониторинг, моделирование и понимание.
В настоящее время такие протоколы (XML-RPC и SOAP) являются интересным способом слияния RPC-методов и текстовых потоков в Unix. Протоколы XML-RPC и SOAP, будучи текстовыми и прозрачными, более приемлемы для Unix-программистов, чем небезопасные и тяжеловесные двоичные форматы сериализа-ции, на смену которым они приходят. Несмотря на то, что они не решают всех глобальных проблем, указанных Танденбаумом и ван Ренессом, они действительно отчасти комбинируют преимущества текстовых потоков и RPC-методов.
7.3.3. Опасны ли параллельные процессы?
Хотя Unix-разработчики давно привыкли к вычислениям с помощью взаимодействующих процессов, среди них нет собственной традиции использования параллельных процессов (процессов, которые совместно используют все выделенное им адресное пространство). Параллельные процессы представляют собой недавнее заимствование извне, и тот факт, что Unix-программисты обычно испытывают к ним неприязнь, не является просто случайностью или исторически непредвиденным поворотом событий.
С точки зрения управления сложностью параллельные процессы являются плохой заменой легковесным процессам с собственными адресными пространствами. Идея параллельных процессов естественна для операционных систем с дорогим созданием подпроцессов и слабыми IPC-средствами.
По определению, несмотря на то, что дочерние параллельные процессы главного процесса обычно обладают отдельными наборами локальных переменных, они совместно йсцользуют ту же глобальную память. Задача управления конфликтами и критическими областями в данном общем адресном пространстве является крайне сложным и богатым источником глобальной сложности и ошибок. Она может быть решена, однако по мере того, как растет сложность одного режима блокировки, соответственно растет вероятность конкуренции и взаимоблокировок благодаря непредвиденному взаимодействию.
Параллельные процессы являются источником ошибок, поскольку они могут чрезмерно просто получить слишком много сведений о внутренних состояниях друг друга. Не существует автоматической инкапсуляции, как это было бы между процессами с обособленными адресными пространствами, которые для обмена данными должны явно использовать IPC-методы. Таким образом, программы, разделенные на параллельные процессы, страдают не только от обычных проблем, связанных с конфликтами, но и от целых новых категорий ошибок, зависимых от синхронизации, которые крайне трудны даже для воспроизведения, не говоря об их устранении.
Разработчики параллельных процессов "сопротивляются" данной проблеме. Недавние реализации и стандарты демонстрируют возрастающей интерес к обеспечению локальной памяти процесса, которая предназначена для ограничения проблем, возникающих из-за совместного использования глобального адресного пространства. По мере того как API-интерфейсы двигаются в данном направлении, программирование с использованием параллельных процессов начинает все более походить на управляемое использование общей памяти.
Параллельные процессы часто препятствуют абстракции. В целях предотвращения взаимоблокировки часто требуется знать, используются ли в применяемой библиотеке параллельные процессы, чтобы избежать проблем взаимоблокировок, и если да, то как. Подобным образом на использование параллельных процессов в библиотеке могло бы воздействовать использование параллельных процессов на уровне приложения.
Дэвид Корн.
В дополнение к вышесказанному, использование параллельной обработки приводит к снижению производительности, что, конечно же, умаляет ее преимущества по сравнению с традиционным разделением процессов. Хотя параллельная обработка может "избавиться" от некоторых издержек быстрого переключения контекста процессов, блокировка общих структур данных с целью предотвратить пересечение параллельных процессов, может быть такой же дорогостоящей.
Х-сервер, способный выполнять буквально миллионы операций в секунду, не разделяется на параллельные процессы. В нем используется цикл poll/select. Многочисленные усилия создать мультипроцессную реализацию привели к негативным результатам. Цена блокировки и разблокировки становится слишком высокой для систем настолько же чувствительных к производительности, насколько чувствительны к ней графические серверы.
Джим Геттис.
Данная проблема является фундаментальной и продолжает оставаться спорной в проектировании яйер Unix для симметричной многопроцессорной обработки. По мере того как блокировка ресурсов становится все более точной, задержка ввиду издержек блокировки может довольно быстро превысить преимущества от блокировки меньшего объема оперативной памяти.
Одна из трудностей, связанных с параллельными процессами, заключается в том, что стандарты данной технологии до середины 2003 года оставались слабыми и не-доопределенными. Теоретически согласующиеся библиотеки для таких Unix-стандартов, как POSIX (1003.1с) могут, тем не менее, проявить опасные различия при функционировании на различных платформах, особенно в аспекте сигналов, взаимодействия с остальными методами IPC и времени освобождения ресурсов. Операционные системы Windows и классическая MacOS обладают собственными моделями параллельной обработки и средствами прерывания, которые очень отличаются от имеющихся в Unix и часто требуют значительных усилий при переносе даже простых конструкций. Вследствие этого рассчитывать на переносимость программ, использующих параллельные процессы, не приходится.
Более широкое обсуждение данного вопроса представлено в статье "Why Threads Are a Bad Idea" [59].
7.4. Разделение процессов на уровне проектирования
Рассмотрим конкретные рекомендации по использованию описанных выше методов.
Прежде всего, необходимо отметить, что временные файлы, более интерактивный способ связи главного/подчиненного процессов, сокеты, RPC и все остальные методы двунаправленного межпроцессного взаимодействия являются эквивалентными на некотором уровне — все они представляют собой только способы обмена данными во время работы программ. Большую часть из того, что делается сложным способом с использованием сокетов или общей памяти, можно было бы реализовать примитивным путем, используя временные файлы в качестве почтовых ящиков и сигналы для доставки уведомлений. Отличия сосредоточены на границах и состоят в том, как программы устанавливают соединения, где и когда выполняется маршалинг и демаршалинг сообщений, какого рода проблемы буферизации могут возникнуть и каковы элементарные гарантии, получаемые с помощью сообщений (т.е. до какой степени можно быть уверенным, что результат одной операции отправки с одной стороны отразится в виде одного события получения на другой стороне).
При рассмотрении PostgreSQL было отмечено, что эффективным способом сдерживания сложности является разделение приложения на пару "клиент-сервер". Клиент и сервер PostgreSQL сообщаются посредством протокола прикладного уровня через сокеты, однако в модели проектирования изменилось бы очень немногое, если бы они использовали любой другой двунаправленный IPC-метод.
Данный вид разделения является особенно эффективным в ситуациях, когда множество экземпляров приложения должны управлять доступом к ресурсам, которые используются ими совместно. Управлять всем распределением ресурсов может один серверный процесс, или каждый из взаимодействующих равноправных процессов может принимать ответственность за некоторый критический ресурс.