Программа на Акторном Прологе состоит из параллельных процессов. Процессы взаимодействуют между собой при помощи сообщений. В Акторном Прологе используются два типа сообщений, вместо одного, как в классической объектно-ориентированной модели вычислений. При этом оба типа сообщений в Акторном Прологе являются строго асинхронными, то есть процессы никогда не приостанавливаются для обмена информацией. Отсутствие синхронизации процессов в языке приводит к необычной парадигме программирования, основную идею которой можно сформулировать следующим образом. В традиционных моделях параллельного программирования процесс приостанавливается, если данные, необходимые ему для дальнейших вычислений, ещё не готовы. В Акторном Прологе процесс не ждёт появления всех необходимых данных, вместо этого он осуществляет вычисления с теми данными, которыми располагает в данный момент. Например, если процесс должен вывести на экран сумму списка чисел, который ещё не вычислен, он выведет сумму элементов пустого или неполного списка. В дальнейшем, каждый раз, когда процесс будет получать уточнённый список, он будет соответствующим образом изменять выведенные результаты. Другими словами, каждый раз при получении новой информации извне процесс будет повторно доказывать некоторые акторы, чтобы модифицировать логический вывод и привести его в соответствие с новым состоянием внешней среды. Достоинства описанной парадигмы асинхронного программирования на Акторном Прологе заключаются в том что:
Конечно, использование средств программирования более высокого уровня приводит к дополнительным издержкам. В частности:
Процессы и сообщения в Акторном Прологе обозначаются очень просто. Начнём с обозначения процессов. 1. Обозначение процессовПроцесс это экземпляр класса, предложения которого выполняются параллельно по отношению к другим процессам. Чтобы объявить процесс, надо просто написать в соответствующем конструкторе экземпляра класса двойные скобки вместо одинарных. Рассмотрим пример P1.A, расположенный в каталоге Concur. Пример 1. Определение процесса.------------------------------------------- -- An example of Actor Prolog program. -- -- (c) 2002, Alexei A. Morozov, IRE RAS. -- -- A definition of one process. -- ------------------------------------------- project: (('MyClass')) ------------------------------------------- class 'MyClass': -- con = ('Report'); -- [ Message:- con ? show, con ? writeln( "I have received " "a message:"), con ? set_color('Blue'), con ? writeln(Message), con ? set_color('Black'). ] ------------------------------------------- В принципе, все элементы этой программы мы уже рассмотрели в предыдущих разделах. Целевым утверждением программы объявляется процесс, экземпляр класса 'MyClass'. У класса 'MyClass' есть один слот con, значением которого является экземпляр предопределённого класса 'Report', реализующего управление текстовыми окнами. Предложение класса написано с использованием метасредства языка, которое мы ещё не рассматривали. Смысл его состоит в том, что любой предикат, вызванный в мире 'MyClass', может быть унифицирован с переменной Message в заголовке предложения. Следовательно, при получении любого неизвестного заранее сообщения, предложение будет вызвано; оно напечатает полученное сообщение в текстовом окне синим цветом. Например, во время создания процесса в окне будет напечатан предикат goal, который автоматически вызывается при создании экземпляров классов. |
Рис. 1.1. Печать сообщений в текстовом окне.
Этот процесс мы будем использовать в качестве элементарного кирпичика при объяснении механизмов передачи информации между процессами в Акторном Прологе. Различаются несколько состояний процессов, в зависимости от состояния принадлежащих им акторов и некоторых других факторов, которые мы рассмотрим позже. Двумя основными состояниями процесса являются:
Состояние процесса изменяется в результате обработки посылаемых ему сообщений.
2. Потоковые сообщенияПотоковые сообщения это наиболее простой из двух типов сообщений, используемых в Акторном Прологе. Потоковые сообщения это данные, передаваемые через общие переменные процессов. При этом общие переменные процессов просто выполняют роль общих переменных логических акторов, принадлежащих различным процессам. То есть изменение значения общей переменной, сделанное каким-либо процессом, вызывает повторное доказательство некоторых акторов в процессах, присоединённых к этой общей переменной. Рассмотрим пример Flow1.A, расположенный в каталоге Concur. Пример 2. Передача потокового сообщения.------------------------------------------- -- An example of Actor Prolog program. -- -- (c) 2002, Alexei A. Morozov, IRE RAS. -- -- Transmission of flow message. -- ------------------------------------------- project: (('Flow1')) ------------------------------------------- Экземпляр класса 'Flow1' содержит два процесса - p1 и p2. Первый из них - экземпляр класса 'Receiver', а второй - экземпляр класса 'Sender'. Процессы связаны общей переменной V, через которую будет передано потоковое сообщение. Обратите внимание на использование ключевого слова protecting в определении процесса, посылающего сообщение. Это ключевое слово сообщает транслятору, что значение порта output посылающего процесса должно быть защищено от изменения со стороны других процессов, порты которых не объявлены "защищающими". Таким образом, данные будут передаваться строго в одном направлении, из процесса p2 в процесс p1. class 'Flow1': -- p1 = (('Receiver', input=V)); p2 = (('Sender', protecting: output=V)); -- [ goal. ] ------------------------------------------- Экземпляр класса 'Receiver' устроен также очень просто. Актор, соответствующий предикату goal этого класса, печатает в текстовом окне значение слота input. Следовательно, любое изменение значения этого слота вызывает повторное доказательство актора и вывод нового сообщения в текстовом окне. class 'Receiver': -- input; -- con = ('Report'); -- [ goal:- con ? write("Common variable= "), con ? set_color('Blue'), con ? writeln(input), con ? set_color('Black'). ] ------------------------------------------- Экземпляр класса 'Sender' выполняет одно-единственное действие. Предикат goal, автоматически вызываемый во время создания этого экземпляра класса, присваивает слоту output строку текста "Message". class 'Sender': -- output; -- [ goal:- output== "Message". ] ------------------------------------------- Процессы и связывающую их общую переменную можно изобразить графически следующим образом: |
Рис. 2.1. Графическое изображение потоковых сообщений.
Теперь запустим программу и посмотрим, что она напечатает на экране. |
Рис. 2.2. Передача потокового сообщения.
Обратите внимание, что процесс p1 начал работать, не дожидаясь данных из процесса p2. Поэтому вначале он напечатал значение #. Константа # используется в Акторном Прологе в качестве начального значения общих переменных процессов, а также для других вспомогательных целей. После изменения общей переменной V процессом p2, процесс p1 осуществил повторное доказательство своего актора, который напечатал новое значение общей переменной. Завершая рассмотрение потоковых сообщений, заметим, что эта разновидность сообщений по своей природе обладает следующими свойствами:
Для реализации передачи информации с буферизацией в Акторном Прологе используется второй тип сообщений, а именно, прямые сообщения. 3. Прямые сообщенияПрямые сообщения являются асинхронным аналогом обычного вызова методов в классической объектно-ориентированной модели вычислений. Прямые сообщения это просто вызов предложений одного процесса из другого. В отличие от потоковых сообщений, прямые сообщения:
В зависимости от правил обработки полученного сообщения различаются две разновидности прямых сообщений - "переключающие прямые сообщения" и "информационные прямые сообщения". Они отличаются тем, что:
Вторым важным отличием переключающих прямых сообщений и информационных прямых сообщений является то, что:
Рассмотрим пример передачи прямых сообщений между процессами Direct1.A в каталоге Concur. Пример 3. Передача прямых сообщений.------------------------------------------- -- An example of Actor Prolog program. -- -- (c) 2002, Alexei A. Morozov, IRE RAS. -- -- Transmission of direct message. -- ------------------------------------------- project: (('Direct1')) ------------------------------------------- Экземпляр класса 'Direct1' содержит два процесса - p1 и p2. Как и в предыдущем примере, первый из них - экземпляр класса 'Receiver', а второй - экземпляр класса 'Sender'. Мир p1 передаётся в качестве параметра конструктору мира p2, чтобы процесс p2 послал ему прямые сообщения. class 'Direct1': -- p1 = (('Receiver')); p2 = (('Sender', target=p1)); -- [ goal. ] ------------------------------------------- Класс 'Receiver' принимает любые прямые сообщения и печатает их в текстовом окне. class 'Receiver': -- con = ('Report'); -- [ Message:- con ? show, con ? writeln( "I have received " "a message:"), con ? set_color('Blue'), con ? writeln(Message), con ? set_color('Black'). ] -------------------------------------------
Класс 'Sender' посылает два прямых сообщения. Для посылки переключающих прямых сообщений в Акторном Прологе используется инфикс " class 'Sender': -- target; -- [ goal:- target << p(1,2,3), target <- q(7,8,9). ] ------------------------------------------- Для графического изображения переключающих прямых сообщений и информационных прямых сообщений мы рекомендуем использовать следующие символы: |
Рис. 3.1. Графическое изображение прямых сообщений.
Вот что программа напечатала на экране: |
Рис. 3.2. Передача прямых сообщений.
Обратите внимание, что переключающее сообщение было обработано принимающим процессом раньше, чем прямое. В Акторном Прологе переключающие прямые сообщения всегда имеют больший приоритет, чем информационные прямые сообщения. Заметим также, что потоковые сообщения имеют больший приоритет, чем прямые. На этом мы завершаем рассмотрение процессов и сообщений в Акторном Прологе. О некоторых других средствах языка, связанных с параллельными вычислениями и передачей информации между процессами, будет рассказано подробнее в следующих разделах. |
Оглавление |