Опубликован: 23.10.2005 | Доступ: свободный | Студентов: 4086 / 201 | Оценка: 4.44 / 4.19 | Длительность: 33:04:00
Специальности: Программист
Лекция 12:

Параллельность, распределенность, клиент-сервер и Интернет

Аннотация: Как и люди, компьютеры могут объединяться в команды для достижения результатов, которые ни один из них не может получить в одиночку, но в отличие от людей они могут выполнять много дел одновременно (или делать вид, что делают их одновременно) и делать их хорошо. Однако до сих пор в обсуждении неявно предполагалось, что вычисление является последовательным, т. е. управляется одной цепочкой команд. Сейчас мы увидим, что получится, если отказаться от этого предположения и перейти к рассмотрению параллельных вычислений.
Ключевые слова: система типов, клиент-сервер, сеть, Интернет, эволюция, слово, компонент, операции, вычисление, команда, процессор, ветвь, приложение, Windows, файл, concurrent, configuration file, отображение, физический ресурс, предусловие, множественное наследование, Дополнение, multiprocessing, multiprogramming, object request broker, распределенные вычисления, архитектура клиент-сервер, разделение ресурсов, система общего назначения, внешний наблюдатель, мэйнфрейм, пассивное ожидание, параллельное вычисление, CORBA, object manager, OLE, activex, интероперабельность, interoperability, IDL, interface definition, всемирная паутина, апплет, файловый ввод/вывод, интранет, внутренняя сеть, параллельная обработка, поддержка, место, единица, компьютер, алгоритм, управление принтером, параллельное программирование, Ada, время выполнения, активный объект, механизм синхронизации, consume, simula, единичное наследование, параллельный процесс, создание процесса, потоки управления, concurrency control, expandability, defer, Макинтош, модель задач, vision, переключение контекста, PVM, virtual machine, ACE, instance, реконфигурация, определение процессов, фактический аргумент, формальный аргумент, развернутый тип, subsystem, ссылочный тип, clone, универсальный класс, распределение ресурсов, reserved, захват семафора, бинарный семафор, критический интервал, hold, modula-2, процедуры монитора, порядок выполнения процессов, reader, denial, Occam, транспьютер, transputer, модель вычислений, множество состояний, pooling, чередование, класс приложений, родительский класс, hybrid, ленивые вычисления, detachable, базисный тип, тупик, отношение, representation, capacity, спецификатор, инкапсуляция, постусловие, основная модель, класс, VIP, статическое связывание, fail, retry, yield, demand-paging, владелец ресурсов, разделяемый ресурс, завершение операций, interruptable, параллельная программа, EAT, launch, бинарное дерево, косвенная рекурсия, ресурсы операции, отложенная операция, возобновление вычислений, resume, coroutine, UNIQUE, активный процесс, физическая система, Elevation, очередь запросов, pending, dispatching, Watchdog, queue, параграф, pre, инвариант, Аксиоматизация, числитель, cond, правильная программа, доказательство, deferred class, challenge, функция с побочным эффектом, спецификация программы, общие критерии, tools, object-oriented programming, программирование, ARIS, CSP, архив, billing, CCS, concurrent system, communications, ACM, работ, наследование, подтип, формальная спецификация, цитирование, операционная система, GUID, activity, удаленный вызов процедур, Синхронный, целочисленный семафор, запуск системы

Параллельность - это не новый предмет, но долгое время интерес к ней ограничивался, в основном, четырьмя областями применения: операционными системами, сетями, реализацией систем управления базами данных и высокопроизводительными научными программами. Хотя эти области стратегически важны и престижны, лишь небольшая часть программистского сообщества вовлечена в их разработку.

Но положение дел изменилось. Параллельность быстро становится необходимой во всех видах приложений, включая такие, которые традиционно представлялись как существенно последовательные по своей природе. Наши системы не просто параллельные, они, будучи или нет системами типа клиент-сервер, должны все больше становиться распределенными по сетям, включая сеть сетей - Интернет. Эта эволюция делает особенно настоятельным центральный вопрос этой лекции: можно ли применять ОО-идеи в контексте параллельности и распределенности?

Это не только возможно: объектная технология может помочь разрабатывать параллельные и распределенные приложения просто и элегантно.

Предварительный просмотр

Как и обычно, при обсуждении параллелизма мы не предложим заранее подготовленный ответ, но вместо этого тщательно построим решение, исходя из детального анализа проблемы и изучения различных путей ее решения, включая и некоторые тупиковые. Хотя такая тщательность необходима для глубокого понимания рассматриваемых методов, она могла бы привести читателя к мысли об их большой сложности, что было бы непростительно, так как тот параллельный механизм, к которому мы в конце придем, на самом деле отличается неправдоподобной простотой. Чтобы избежать такого риска, начнем с обзора этого механизма, отложив обоснования на потом.

Если вам не нравится забегать вперед и вы предпочитаете последовательное изучение предмета и продвижение к развязке драмы шаг за шагом и вывод за выводом, то пропустите следующую страницу с резюме и переходите к слудующему разделу.

Расширение, полностью охватывающее параллельность и распределенность, будет самым минимальным из всех возможных: к последовательным обозначениям добавляется единственное новое ключевое слово - separate. Почему это возможно? Мы используем основную схему ОО-вычислений: вызов компонента x.f (a), выполняемый от имени некоторого объекта O1, и вызывающий компонент f объекта O2, присоединенного к x с аргументом a. Но сейчас вместо одного процессора, выполняющего операции всех объектов, мы рассчитываем на возможность использовать разные процессоры для O1 и O2, так что вычисление O1 может продолжаться, не ожидая завершения указанного вызова, поскольку он обрабатывается другим процессором.

Поскольку результат вызова сейчас зависит от того, обрабатываются ли объекты одним процессором или несколькими, в тексте программы об этом должно быть точно сказано для каждой сущности x. Поэтому требуется новое ключевое слово: вместо того, чтобы объявлять просто x: SOME_TYPE, будем объявлять x: separate SOME_TYPE, чтобы указать, что x обрабатывается отдельным процессором, так что вызовы с целью x могут выполняться параллельно с остальным вычислением. При таком объявлении всякая команда создания create x.make (...) будет порождать новый процессор - новую ветвь управления - для обработки будущих вызовов x.

Нигде в тексте программы не требуется указывать, какой именно процессор нужно использовать. Все, что утверждается посредством объявления separate - это то, что два объекта обрабатываются различными процессорами, и это существенно влияет на семантику системы. Назначение конкретного процессора можно перенести на время исполнения. Мы также не устанавливаем заранее точную природу процессора: он может быть реализован как часть оборудования (компьютера), но может также оказаться заданием (процессом) операционной системы или, в случае многопоточной ОС, стать одной из нитей (потоков) задания. С точки зрения программы "процессор" - это абстрактное понятие; одно и то же параллельное приложение может выполняться на совершенно разных архитектурах (на одном компьютере с разделением времени, в распределенной сети со многими компьютерами, несколькими потоками одного задания под Unix или Windows) без всякого изменения его исходного текста. Все, что потребуется изменить, - это "Файл параллел ьной конфигурации" -_ ("Concurrency Configuration File"), задающий отображение абстрактных процессоров на физические ресурсы.

Определим ограничения, связанные с синхронизацией. Эти соглашения достаточно просты:

  • Клиенту не требуется никакого специального механизма для повторной синхронизации с сервером после того, как вызов x.f (a) для объявленной separate сущности x пойдет на параллельное выполнение. Клиент будет ждать столько, сколько необходимо, когда он запрашивает информацию об объекте с помощью вызова запроса, как в операторе value := x.some_query. Этот автоматический механизм называется ожидание по необходимости (wait by necessity).
  • Для получения исключительного доступа к отдельному объекту O2 достаточно использовать присоединенную к нему сущность a, объявленную как separate, в качестве аргумента соответствующего вызова, например, r(a).
  • Если у подпрограммы имеется предусловие, содержащее аргумент, объявленный как separate (например, такой как a ), то клиенту придется ждать, пока это предусловие не выполнится.
  • Для контроля за работой ПО и предсказуемости результатов (в частности, поддержания инвариантов класса) нужно разрешать процессору, ответственному за объект, выполнять в каждый момент времени не более одной процедуры.
  • Однако иногда может потребоваться прервать выполнение некоторой процедуры, уступив ресурсы новому более приоритетному клиенту. Клиент, которого прервали, сможет произвести соответствующие корректирующие мероприятия; наиболее вероятно, что он повторит попытку после некоторого ожидания.

Это описание охватывает основные свойства механизма, позволяющего строить продвинутые параллельные и распределенные приложения, в полной мере используя ОО-методы от множественного наследования до проектирования по контракту. Далее мы рассмотрим этот механизм детально, забыв на время то, что прочли только что в этом кратком обзоре.

Возникновение параллельности

Вернемся к началу. Чтобы понять, как эволюция потребовала от разработчиков сделать параллельность частью их образа мысли, проанализируем различные виды параллельности. В дополнение к традиционным понятиям мультипроцессорной обработки (multiprocessing) и многозадачности (multiprogramming) за несколько последних лет было введено два новых понятия: посредники запроса объекта (object request brokers) и удаленное выполнение в Сети.

Мультипроцессорная обработка

Чем больше хочется использовать огромную вычислительную мощь, тем меньше хотелось бы ждать ответа компьютера (хотя мы вполне миримся с тем, что компьютер ждет нас). Поэтому, если один вычислитель не выдает требуемый результат достаточно быстро, то приходится использовать несколько вычислителей, работающих параллельно. Эта форма параллельности называется мультипроцессорной обработкой.

Впечатляющие приложения мультипроцессорности привлекли исследователей, надеющихся на работу сотен компьютеров, разбросанных по сети Интернет, в то время, когда их (по-видимому, согласные с этим) владельцы в них не нуждаются, к решению задач, требующих интенсивных вычислений, таких, например, как взлом криптографических алгоритмов. Такие усилия прилагаются не только в компьютерных исследованиях. Ненасытное требование Голливудом реалистичной компьютерной графики подбрасывает топливо в топку прогресса этой области: в создании фильма Toy Story, одного из первых, в котором играли только искусственные персонажи (люди их лишь озвучивали), участвовала сеть из сотни мощных рабочих станций - это оказалось более экономичным, чем привлечение сотни профессиональных мультипликаторов.

Мультипроцессорность повсеместно используется в высокоскоростных научных вычислениях при решении физических задач большой размерности, в инженерных расчетах, метеорологии, статистике, инвестиционных банковских расчетах.

Во многих вычислительных системах часто применяется некоторый вид балансирования нагрузки ( load balancing ):автоматическое распределение вычислений по разным компьютерам, доступным в данный момент в локальной сети некоторой организации.

Другой формой мультипроцессорности является вычислительная архитектура, называемая клиент-сервер (client-server computing), присваивающая разные роли компьютерам в сети: несколько самых крупных и дорогих машин являются "серверами", выполняющими большие объемы вычислений, работающими с общими базами данных и содержащими другие централизованные ресурсы. Более дешевые машины сети, расположенные у конечных пользователей, выполняют децентрализованные задания, обеспечивая интерфейс и проведение простых вычислений, передавая серверам все задачи, не входящие в их компетенцию, получая от них результаты решений.

Нынешняя популярность подхода клиент-сервер представляется колебанием маятника в направлении, противоположном тенденциям предыдущего десятилетия. В 60-х и 70-х архитектуры были централизованными, заставляя пользователей бороться за ресурсы. Революция, вызванная появлением персональных компьютеров и рабочих станций в 80-х, наделила пользователей ресурсами, ранее приберегаемыми Центром (на промышленном жаргоне "стеклянным домом"). Но вскоре стало очевидным, что персональный компьютер может далеко не все и некоторые ресурсы должны быть общими (разделяться). Это объясняет появление архитектуры клиент-сервер в 90-х. Постоянный циничный комментарий - мы возвратились к архитектуре нашей юности: одна центральная машина - много терминалов, только с более дорогими терминалами, называемыми сейчас рабочими станциями, - на самом деле, не вполне оправдан: промышленность просто ищет путем проб и ошибок подходящее соотношение между децентрализацией и разделением ресурсов.

Многозадачность

Другой главной формой параллельности является многозадачность, когда один компьютер выполняет одновременно несколько заданий.

Если рассмотреть системы общего назначения (исключая процессоры, встроенные в оборудование от стиральных машин до самолетов и однообразно повторяющие фиксированный набор операций), то компьютеры почти всегда являются многозадачными, выполняя задачи операционной системы параллельно с задачами приложений. Строго говоря, параллелизм при многозадачности скорее мнимый, чем настоящий: в каждый момент времени процессор на самом деле выполняет одно задание, но время переключения с одного задания на другое столь коротко, что внешний наблюдатель может поверить в то, что они выполняются одновременно. Кроме того, сам процессор может делать некоторые вещи параллельно (как, например, в современных схемах выборки команд во многих компьютерах, когда за один такт одновременно с выполнением текущей команды загружается следующая) или может на самом деле быть комбинацией нескольких вычисляющих компонентов, так что многозадачность переплетается с мультипроцессорностью.

Обычным применением многозадачности является разделение времени компьютера (time-sharing), позволяющее одной машине обслуживать одновременно нескольких пользователей. Но, за исключением случая самых мощных компьютеров - "мэйнфреймов", эта идея сегодня представляется гораздо менее привлекательной, чем в те времена, когда компьютеры были большой редкостью. Сегодня наше время является более ценным ресурсом, поэтому хотим, чтобы система выполняла для нас несколько дел одновременно. В частности, многооконный интерфейс пользователя позволяет одновременно выполнять несколько приложений: в одном окне мы осуществляем поиск в Интернете, в другом - редактируем документ, а еще в одном компилируем и отлаживаем некоторую программу. Все это требует мощных механизмов параллельности.

Ответственность за предоставление каждому пользователю многооконного многозадачного интерфейса лежит на операционной системе. Но все больше пользователей разрабатываемых нами программ хотят иметь параллельность внутри одного приложения. Причина все та же: они знают, что вычислительные мощности доступны в изобилии, и не хотят сидеть в пассивном ожидании. Так что, если получение пришедших по электронной почте сообщений требует много времени, то хотелось бы иметь возможность в это же время посылать исходящие сообщения. В хорошем Интернет-браузере можно получать доступ к новому сайту во время загрузки страниц из другого сайта. В системе биржевой торговли можно одновременно получать информацию с нескольких бирж, покупая в одном месте, продавая в другом и управляя портфелем клиента в третьем.

Именно эта необходимость распараллеливания внутри одного приложения неожиданно выдвинула область параллельных вычислений на передний край разработки ПО и вызвала интерес к ней, в кругах далеко выходящих за рамки первоначальных спонсоров. Между тем традиционные приложения параллельности не потеряли своего значения в новых разработках, относящихся к операционным системам, Интернету, локальным сетям и научным вычислениям - всюду, где непрерывный поиск скорости требует еще более высокого уровня многозадачности.

Посредники запросов объектов (брокеры объектных запросов - Object Request Broker)

Другим важным недавним достижением явилось появление предложения CORBA от Группы управления объектами (Object Management Group) и архитектуры OLE 2/ActiveX от фирмы Майкрософт. Хотя их окончательные цели, детали и рынки различны, оба предложения обещают существенное продвижение в направлении распределенных вычислений1В момент написания этой книги понятия Web-сервиса еще не существовало..

Общая цель состоит в том, чтобы сделать объекты и услуги различных приложений доступными друг для друга наиболее удобным образом локально или через сеть. Усилия CORBA направлены, в частности, на достижение интероперабельности (interoperability).

  • Приложения, поддерживающие CORBA, могут взаимодействовать между собой, даже если они основаны на "посредниках запроса объектов" разных производителей.
  • Интероперабельность применяется также и на уровне языка: приложение на одном из поддерживаемых языков может получить доступ к объектам приложения, написанного на другом языке. Взаимодействие происходит с помощью внутреннего языка, называемого IDL (язык определения интерфейса - Interface Definition Language); у поддерживаемых языков имеется официальная привязка к IDL, в которой определено, как конструкции языка отображаются на конструкции IDL.

IDL - это общий знаменатель ОО-языка, сконцентрированного на понятии интерфейса. Интерфейс IDL для класса по духу похож на его краткую форму, хотя и более примитивную (в частности, IDL не поддерживает утверждений); в нем описывается набор компонентов, доступных на некотором уровне абстракции. По классу, написанному на ОО-языке, с помощью инструментальных средств будет выводиться IDL-интерфейс класса, представляющий интерес для клиентов. Клиент, написанный на том же или на другом языке, может через этот IDL-интерфейс получать доступ по сети к компонентам, предоставляемым поставщиком класса.

Удаленное выполнение

Другим достижением поздних 90-х является механизм для удаленного выполнения программ через Всемирную Паутину (World-Wide Web).

Первые Веб-браузеры сделали не только возможным, но и весьма удобным использование информации, хранящейся на удаленных компьютерах, расположенных по всему миру, и переходы по логическим связям или гиперссылкам с помощью одного щелчка мыши. Но это был пассивный механизм: некто готовит некоторую информацию, а все остальные получают к ней доступ в режиме чтения.

Следующим шагом был переход к достижению активности, когда щелчок по ссылке вызывает выполнение некоторой операции. Это предполагает наличие внутри браузера некоторой машины выполнения, распознающей загружаемую информацию как выполняемый код и выполняющей его. Эта машина может быть встроенной частью браузера или динамически присоединяется к нему в ответ на запрос соответствующего типа. Последнее известно как подключаемый (plug-in) механизм и предполагает доступность бесплатной загрузки его из Интернета.

Эта идея впервые сделалась популярной благодаря Java, когда машина исполнения Java-программ стала общедоступной. С тех пор появилась возможность подключения и других механизмов. Другим направлением стала трансляция исходных языков в код широко распространенной машины такой, например, как машина исполнения Java; действительно, несколько производителей компиляторов начали создавать генераторы "байт-кода" языка Java (это переносимый код низкого уровня, который может исполняться Java-машиной).

Для нотации, используемой в этой книге, работа шла в двух направлениях: у фирмы ISE имеется свободно распространяемая машина исполнения программ в этой нотации и в то же время разрабатывается проект порождения байт-кода языка Java.

При любом из этих подходов возникают проблемы безопасности: насколько можно доверять чужому приложению? Неосторожный щелчок по невинно выглядящей гиперссылке способен запустить нехорошую программу, портящую файлы компьютера или крадущую личную информацию. Следует самому быть осторожным, хотя ответственность лежит на поставщике исполняющей машины.

Решение проблемы предполагает использование тщательно разработанных и сертифицированных исполняющих машин и библиотек, пришедших из авторитетных источников. Часто у них две версии:

  • Одна допускает неограниченное использование в Интернет и основана на строгих ограничениях возможностей исполняющей машины.

    В средствах, предоставляемых ISE, в библиотеке ввода-вывода этой ограниченной версии допускается только чтение и запись с терминала и на терминал, а не в файлы. Механизм "external" для подключения внешних программ также отключен, так что плохое приложение не сможет причинить вред, например, с помощью перехода к С для выполнения манипуляций с файлами. "Виртуальная машина" языка Java также использует драконовские ограничения того, что разрешается делать апплетам, приходящим из Интернета, с файловой системой вашего компьютера.

  • В другой версии ограничений существенно меньше либо нет вовсе, она дает возможность использовать всю мощь библиотек, в частности, файлового ввода-вывода. Она предназначена для приложений, работающих в безопасной Интранет (внутренней сети компании), а не на диком пространстве Интернета.

Несмотря на опасения ненадежности перспектива неограниченного удаленного выполнения - нового шага на пути продолжающейся революции в распространении ПО - породила огромный неослабевающий интерес.