Joyce — безопасный язык программирования для параллельных вычислений , разработанный Пером Бринчом Хансеном в 1980-х годах. [1] Он основан на последовательном языке Паскаль и принципах взаимодействия последовательных процессов (CSP). Он был создан для устранения недостатков CSP, применяемого в качестве языка программирования, и для предоставления инструмента, в основном для обучения, для реализации распределенных вычислительных систем.
Язык основан на концепции агентов ; одновременно выполняемые процессы, которые взаимодействуют только посредством использования каналов и передачи сообщений . Агенты могут активировать субагенты динамически и рекурсивно . Разработка Джойса легла в основу языка SuperPascal , также разработанного Хансеном примерно в 1993 году.
Joyce основан на небольшом подмножестве Pascal, дополненном функциями параллелизма, вдохновленными CSP. [2] В следующих разделах описаны некоторые из наиболее новых функций, которые были представлены.
Агент — это процедура, состоящая из набора операторов и, возможно, вложенных определений других агентов. Агент может динамически активировать субагенты, которые выполняются одновременно со своим создателем . Агент может завершить работу только тогда, когда все его субагенты также завершили работу. Например, агент process2
активирует process1
:
агент процесс1 ( x , y : целое число ) ; начинать ...конец ;агент процесс2 () ; использовать процесс1 ; начинать процесс1 ( 9 , 17 ) ; конец ;
Активация агента создает новые экземпляры всех локальных переменных , и значение каждого формального параметра копируется в локальную переменную. Следовательно, агенты не могут получить доступ к переменным других агентов, и им разрешено общаться только через каналы. Это ограничение предотвращает проблемы, связанные с использованием общих переменных, таких как условия гонки .
Агенты общаются через объекты, называемые каналами . Каналы имеют алфавит, определяющий набор символов, которые могут передаваться. Каналы создаются динамически, доступ к ним осуществляется с помощью переменных порта . Тип порта определяется отдельным набором символов, составляющих его алфавит. Символы с несколькими значениями определяются определенным типом. Например:
поток = [ int ( целое число ) , eos ] ;
Символ int(integer)
обозначает символ сообщенияint
, вызываемый любым целочисленным значением. Второе объявление бестипового символа eos
(конец потока) называется сигналом . После определения типа порта можно объявить переменную порта этого типа:
выход: потокв: поток
И тогда сущность канала, внутренняя для создающего его агента, может быть активирована следующим образом:
+выход;
Затем символы можно отправлять и получать по каналам с помощью операторов ввода и вывода в стиле CSP ?
и !
соответственно. Связь может происходить только в том случае, если существует агент-получатель, соответствующий агенту-отправителю. Принимающий агент должен ожидать получения отправляемого типа символа. Например, значение 9, за которым следует eos
символ, отправляется на порт out
:
вне ! int ( 9 ) выход ! Эос
И целочисленное сообщение принимается в переменную соответствующего типа, за которой следует eos
:
получено : целое число в ? int ( получено ) в ? Эос
Заявления опроса основаны на концепции защищенных альтернатив CSP. Оператор опроса состоит из набора операторов, каждый из которых защищен оператором входного канала. Когда связь между передающим агентом и охраной согласована, выполняется охрана, за которой следует соответствующий оператор. Например:
голосование в ? Икс -> х := х + 1 | в ? Y -> y := y + 1конец
Если порт in
контролируется на наличие сигналов X
или Y
, при соответствующей связи соответствующие переменные x
или y
увеличиваются.
Джойс был спроектирован как безопасный язык в том смысле, что компилятор сможет обнаружить все нарушения языковых правил.
Ниже приведен полный пример программы, взятый из оригинальной статьи, посвященной языку программирования Джойса [1] , реализующий алгоритм генерации простых чисел, основанный на методе просеивания для генерации простых чисел . Агенту sieve
отправляется поток целых чисел от его предшественника, первое из которых является простым числом. Он удаляет из потока все кратные этому простому числу и активирует преемника. Это продолжается до тех пор, пока eos
сигнал не распространится по набору сит.
агент сито ( вход , выход : поток ) ; вар больше : логическое значение ; х , у : целое число ; успех : поток ; начать опрос ? int ( x ) -> + succ ; сито ( успех , выход ) ; подробнее := правда | вход ? эос -> выход ! эос ; больше := ложный конец ; а еще делать опрос ? int ( y ) -> если y mod x <> 0 , то успешно ! интервал ( у ) | вход ? эос -> выход ! интервал ( х ) ; успех ! эос ; больше := ложный конец ; конец ;
Следующий агент инициализирует набор ситовых агентов и вводит в них поток целых чисел от 3 до 9999.
простые числа агентов ; используйте создание , просеивание , печать ; вар а , б : поток ; начать + а ; + б ; генерировать ( а , 3 , 2 , 4999 ) ; сито ( а , б ) ; печать ( б ) конец ;
Из-за одновременного выполнения процедур агента традиционную схему последовательного распределения стека нельзя использовать, поскольку записи активации вызовов агента не следуют шаблону «последним пришел — первым вышел». Вместо этого отношения создатель-субагент образуют стек с древовидной структурой. Для реализации такого поведения используется простая схема, которая работает путем выделения новых записей активации наверху стека и связывания записей активации субагентов с записью их создателя. Эти записи освобождаются только тогда, когда агент завершает работу и они оказываются на вершине стека. [3] Эффективность этой схемы зависит от структуры и поведения программы, что в некоторых случаях приводит к неэффективному использованию памяти. Более эффективная схема была реализована в языке Хансена SuperPascal .