Virtual Laboratory Wiki
Advertisement

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

Принципы языка массового параллельного программирования

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

Тут в плане выразительности, конечно, лидером считается Питон. Вероятно, неплохо будет ориентироваться на него, ка основу синтаксиса для элементарных (атомарных) выражений.

1.1. Кстати, из этого следует, что ему было бы полезно иметь перед глазами картинку взаимодействующих процессов. Значит среда программирования для ErPy должна поддерживать подобную нотацию. (+ надо сделать эскизы)

1.2. Для построения обширных библиотек классов процессов, следует воспользоваться принципами ООП (наследование, полиморфизм, инкапсуляция).

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

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

2. Концепция параллельных процессов языка

2.0. Весь мир состоит из множества параллельно работающих процессов.

2.1. Программа состоит из множества параллельных процессов работающих независимо друг от друга.

2.2. Процессы могут общаться между собой посылая друг-другу Сообщения. И другое взаимодействия запрещены. То есть, запрещены, например, процессы работающие на общей памяти: Всегда должен быть Хозяин, приглядывающий за этими тупыми роботами на одном поле, чтобы они не столкнулись и не помешали друг другу. Хотя, для решения подобных задач, возможно, стоит сделать Шаблон языка Хозяин-Работники (Master-Slaves).

2.3. Посылая сообщение процесс не может быть уверен, что его адресат ему ответит или, что он вообще еще существует. Хотя, факт существования (на текущий миг времени) можно, конечно, проверить специальным системным запросом (Типа как крикнуть в темноту: Вася, ты еще здесь?)

2.4. Каждый процесс обладает рядом свойств, по которым к нему можно обращаться снаружи. То есть это типы сообщений (с набором их параметров) которые он может принять. (Аналогом, наверно, могут послужить функции класса в ООП, которые можно вызвать у объекта.) Если процесс запросили свойство (пришло сообщение) которое в нем не реализовано (в текущий момент), то отправитель получает сообщение типа "Не реализовано" (get_off="Отвали!", как говорит девушка, в которой пока не реализовалось желание ответить этому молодому человеку :) ).

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

2.6. Приоритеты задаются в описании свойств при описании процесса. То есть на стороне адресата а не у отправителя сообщения. Только получатель решает в какой последовательности ему обрабатывать накопившиеся сообщения. Но в нем также может быть реализовано свойство по динамическому изменению приоритетов по внешнему запросу (если этого требует задача). По умолчанию, всем свойствам процесса (приемникам сообщений = функциям) назначается некоторый одинаковый "средний" приоритет. Следует предупредить программистов, что бездумная игра с приоритетами может привести к непредсказуемости выполнения сообщений процессами и ужасно запутать общую картину.

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

2.8. Запуск процесса. Процесс запускается другим процессом (либо, первоначально, из виртуальной машины процессов) с помощью оператора new. В качестве параметров такого запуска (кроме параметров передаваемых самому процессу (если нужно)) могут быть правила поддержки работоспособности этого процесса (его Перезапуска, в духе контроллера в Эрланге). При запуске процесса оператором new возвращается PID (Process ID) (цифровой, типа <N.N.N> или тому подобный). Этот PID можно использовать для посылки сообщений данному экземпляру процесса. Также можно (в духе Эрланга) зарегистрировать некоторое глобальное имя для данного процесса, по которому к нему могут обращаться все, кто его знает.

2.8.1. Инициализация процесса. При старте нового экземпляра процесса оператор new его прародителя автоматически пытается обратиться к специально-выделенному свойству init и передать ему все параметры. Если это свойство в порожденном процессе присутствует и параметры вполне согласовались, то происходит его выполнение. иначе выдается get_off.

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

2.10. Внутренние таймеры. Каждому процессу прилагается набор таймеров (в миллисекундах) которыемогут порождать внутренние события, то есть сообщения. Благодаря им Процесс может жить некоторой своей внутренней жизнью, а не только реагировать на внешние воздействия.

3. ООП для процессов.

3.0. В общем и целом ООП для процессов (ООПП) следует принципам обычного ООП для классов и служит для упрощения построения сложных процессов из более мелких.

3.1. Инкапсуляция выполняется автоматически - все переменные (Состояния процесса) только внутренние, побочные эффекты для процессов запрещены.

3.2. Наследование. При описании процессов можно наследовать свойства от других процессов, достаточно указать их имена через запятую. Типа так:

 // начало описания процесса :
 proc Pnew :: P1, P2, ... , Pn ;
   // описание новых переменных состояния процесса Pnew :
   status V1,V2, ... , Vm ;
   // описание новых свойств процесса Pnew :
   fun F1 (A1, ... , Af1)->
     //описаие операторов свойства F1 процесса Р1
   ...
   

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

3.3. Полиморфизм. Новые описания свойств и статусных переменных добавляются к унаследованным от прорадителей. При совпадении заголовков свойств унаследованные свойства заменяются на новые.

M.Netov

Advertisement