Шаблоны соединения обеспечивают способ написания параллельных , параллельных и распределенных компьютерных программ с помощью передачи сообщений . По сравнению с использованием потоков и блокировок, это модель программирования высокого уровня, использующая модель коммуникационных конструкций для абстрагирования от сложности параллельной среды и обеспечения масштабируемости . Его основное внимание уделяется исполнению аккорда между сообщениями, атомарно потребляемыми из группы каналов.
Парадигма | параллельные вычисления , распределенное программирование |
---|---|
Разработчик | INRIA Inria |
Веб-сайт | Инрия Присоединяйтесь |
Основные реализации | |
Присоединяйтесь к Java , Polyphonic C # , Unified Parallel C , Cω , библиотеке Joins , Boost . | |
Под влиянием | |
Присоединяйтесь к исчислению |
Этот шаблон основан на исчислении соединений и использует сопоставление с образцом . Конкретно, это достигается путем определения соединения нескольких функций и / или каналов путем сопоставления параллельных вызовов и шаблонов сообщений. Это тип шаблона параллелизма, потому что он упрощает и делает более гибким для этих объектов взаимодействие и работу с парадигмой многопоточного программирования.
Описание
Шаблон соединения (или аккорд в Cω ) похож на супер-конвейер с синхронизацией и сопоставлением. Фактически, эта концепция резюмируется путем сопоставления и объединения набора сообщений, доступных из разных очередей сообщений , а затем обрабатывает их все одновременно с помощью одного обработчика. [1] Это может быть представлено ключевыми словами, when
чтобы указать первое сообщение, которое мы ожидали, с and
соединением / соединением других каналов и do
запуском некоторых задач с разными собранными сообщениями. Сконструированный шаблон соединения обычно принимает такую форму:
j . Когда ( a1 ). И ( а2 ). ... . И ( ан ). Делать ( d )
Аргумент a1 из When(a1)
может быть синхронным или асинхронным каналом или массив асинхронных каналов. Каждый последующий аргумент ai to And(ai)
(for i > 1
) должен быть асинхронным каналом. [2]
Точнее, когда сообщение совпадает с цепочкой связанных шаблонов, запускается его обработчик (в новом потоке, если он находится в асинхронном контексте), в противном случае сообщение ставится в очередь до тех пор, пока не будет включен один из его шаблонов; если совпадений несколько, выбирается неуказанный шаблон. [3] В отличие от обработчика событий, который одновременно обслуживает одно из нескольких альтернативных событий, вместе со всеми другими обработчиками этого события, шаблон соединения ожидает соединения каналов и конкурирует за выполнение с любым другим включенным шаблоном. [4]
Шаблон соединения определяется набором каналов пи-исчисления. x, который поддерживает две разные операции, отправку и получение, нам нужны два имени исчисления соединения для его реализации: имя канала x для отправки (сообщения) и имя функции x для получения значения (запроса). Смысл определения соединения заключается в том, что вызов x()
возвращает значение, которое было отправлено по каналу x<>
. Каждый раз, когда функции выполняются одновременно, запускается процесс возврата и синхронизируется с другими соединениями. [5]
J :: = // шаблоны соединения | x < y > // шаблон отправки сообщения | x ( y ) // шаблон вызова функции | J | JBIS // синхронизация
С точки зрения клиента, канал просто объявляет метод с тем же именем и подписью. Клиент отправляет сообщение или выдает запрос, вызывая канал как метод. Метод продолжения должен ждать до тех пор, пока один запрос или сообщение не поступит на каждый из каналов, следующих за предложением When продолжения. Если продолжение запускается, аргументы каждого вызова канала удаляются из очереди (таким образом, потребляются) и передаются (атомарно) параметрам продолжения. [6]
В большинстве случаев порядок синхронных вызовов не гарантируется по причинам производительности. Наконец, во время совпадения сообщения, имеющиеся в очереди, могут быть украдены каким-либо промежуточным потоком; действительно, пробужденному потоку, возможно, придется снова ждать. [7]
История
π-исчисление - 1992
Π-исчисление принадлежит к семейству процесса конкрементов , позволяет математический аппарат для описания и анализа свойств параллельного вычисления с использованием названий каналов , которые будут сообщены по каналам себя, и таким образом он способен описать параллельные вычисления которых конфигурация сети может изменение во время вычисления.
Соединение-исчисление - 1993
Шаблоны соединения впервые появились в основополагающем исчислении соединений Фурнета и Гонтье, алгебре асинхронных процессов, разработанной для эффективной реализации в распределенной среде. [8] Соединенное исчисление - это исчисление процессов, столь же выразительное, как и полное π-исчисление . Он был разработан, чтобы обеспечить формальную основу для проектирования распределенных языков программирования, и поэтому намеренно избегает коммуникационных конструкций, встречающихся в других вычислениях процессов, таких как рандеву .
Распределенное объединенное исчисление - 1996 г.
Join-Calculus - это и исчисление передачи имен, и базовый язык для параллельного и распределенного программирования. [9] Вот почему распределенное объединенное исчисление [10] на основе объединенного исчисления с распределенным программированием было создано в 1996 году. В этой работе используются мобильные агенты, в которых агенты являются не только программами, но и основными образами запущенных процессов с их коммуникационными возможностями. .
JoCaml, Funnel и Join Java - 2000
JoCaml [11] [12] и Funnel [13] [14] - это функциональные языки, поддерживающие декларативные шаблоны соединения. Они представляют идеи для непосредственной реализации расчетов процесса в функциональной среде.
Еще одно расширение (не общего) Java, JoinJava , было независимо предложено фон Ицштейном и Кирни. [15]
Полифонический C # - 2002
Карделли, Бентон и Фурнет предложили объектно-ориентированную версию шаблонов соединения для C # под названием Polyphonic C # . [16]
Cω - 2003 г.
Cω - это адаптация исчисления соединений к объектно-ориентированной среде. [17] Этот вариант Polyphonic C # был включен в общедоступный выпуск Cω (он же Comega) в 2004 году.
Scala присоединяется - 2007
Scala Joins - это библиотека для использования шаблона соединения со Scala в контексте расширяемого сопоставления с шаблоном для интеграции объединений в существующую структуру параллелизма на основе субъектов.
Джерланг - 2009 г.
Erlang - это язык, который изначально поддерживает парадигму параллельного, реального времени и распределенного доступа. Параллелизм между процессами был сложным, поэтому сборка проекта нового языка, JErlang ( J означает присоединиться ) с использованием на основе Join-исчислении.
Шаблон соединения в литературе по классическому программированию
«Шаблоны соединения могут использоваться для простого кодирования связанных идиом параллелизма, таких как акторы и активные объекты». [18]
- Барьеры [19]
class SymmetricBarrier { общедоступный синхронный только для чтения . Прибытие канала ; public SymmetricBarrier ( int n ) { // создаем j и инициализируем каналы (исключены) var pat = j . Когда ( Прибытие ); для ( int i = 1 ; i < n ; i ++) pat = pat . И ( Прибытие ); погладить . Сделать (() => { }); } }
- Проблема обедающих философов [20]
var j = Присоединиться . Создать (); Синхронный . Канал [] голоден ; Асинхронный . Канал [] палочка для еды ; j . Иниц ( из голодных , п ); j . Инициализация ( из палочек , п ); для ( int я = 0 ; я < п ; я ++) { var left = палочка для еды [ я ]; var right = палочка для еды [( i + 1 ) % n ]; j . Когда ( голодный [ i ]). И ( слева ). И ( правильно ). Do (() => { eat (); left (); right (); // заменить палочки для еды }); }
- Взаимное исключение [21]
class Lock { public readonly Synchronous . Получение канала ; общедоступный только для чтения Асинхронный . Выпуск канала ; public Lock () { // создаем j и инициализируем каналы (исключены) j . Когда ( Приобрести ). И ( Релиз ). Сделать (() => { }); Выпуск (); // изначально бесплатно } }
- Производители / потребители [22]
class Buffer < T > { общедоступный асинхронный только для чтения . Канал < T > Put ; общедоступный только для чтения Synchronous < T >. Channel Get ; public Buffer () { Присоединиться j = Присоединиться . Создать (); // выделяем объект Join j . Инициализация ( выход пут ); // привязываем его каналы j . Init ( out Get ); j . Когда ( Получить ). И ( Положите ). У // регистр аккорда ( т => { обратный т ; }); } }
- Блокировка чтения и записи [19]
класс ReaderWriterLock { частное чтения Асинхронный . Канал свободен ; частный только для чтения Асинхронный . Канал < int > общий ; public readonly Synchronous . Канал AcqR , AcqW , RelR , RelW ; public ReaderWriterLock () { // создаем j и инициализируем каналы (исключены) j . Когда ( AcqR ). И ( простаивает ). Сделать (() => общий ( 1 )); j . Когда ( AcqR ). И ( поделился ). Сделать ( n => общий ( n + 1 )); j . Когда ( RelR ). И ( поделился ). Do ( n => { if ( n == 1 ) idle (); else shared ( n - 1 ); }); j . Когда ( AcqW ). И ( простаивает ). Сделать (() => { }); j . Когда ( RelW ). Do (() => idle ()); простаивает (); // изначально бесплатно } }
- Семафоры [21]
class Semaphore { общедоступный синхронный только для чтения . Получение канала ; общедоступный только для чтения Асинхронный . Выпуск канала ; public Semaphore ( int n ) { // создаем j и инициализируем каналы (исключены) j . Когда ( Приобрести ). И ( Релиз ). Сделать (() => { }); for (; n > 0 ; n -) Release (); // изначально n бесплатно } }
Основные функции и концепции
- Исчисление соединений : первое проявление паттерна соединения появилось вместе с этим исчислением процессов.
- Передача сообщений : шаблон соединения работает с системой передачи сообщений по параллельной причине.
- Канал : каналы используются для синхронизации и передачи сообщений между одновременно выполняющимися потоками. В общем, канал может быть задействован более чем в одном шаблоне соединения, каждый шаблон определяет другое продолжение, которое может выполняться при вызове канала. [6]
- Синхронный : шаблон соединения может использовать синхронный канал, который возвращает результат. Продолжение синхронного шаблона выполняется в потоке синхронного отправителя. [6]
- Асинхронный : он также может использовать асинхронный канал, который не возвращает результата, но принимает аргументы. Продолжение асинхронного шаблона выполняется во вновь созданном потоке. Шаблон соединения может быть чисто асинхронным при условии, что его продолжением является подпрограмма, а его предложение When перечисляет только асинхронные каналы. [6]
- Комбинируйте синхронный и асинхронный: объединение объявлений синхронного и асинхронного буфера даст модуль, который поддерживает два типа связи потребителей. [6]
- Планировщик : существует планирование между шаблонами соединения (например, планировщик циклического перебора, планировщик первого совпадения). [6]
- Шаблоны проектирования : шаблон соединения - это, прежде всего, шаблон поведения и шаблон параллелизма.
- Параллельное программирование : выполняется параллельно.
- Сопоставление с образцом : образец соединения работает с задачами сопоставления.
- Параллельное программирование : выполняет задачи параллельно.
- Распределенное программирование : с помощью этого шаблона задания могут быть распределены по разным агентам и средам.
- Программная транзакционная память : Программная транзакционная память (STM) является одной из возможных реализаций для связи между узлами.
- Перекрытие : шаблон может допускать объявления шаблонов для перекрывающихся наборов каналов.
Домен приложения
Мобильный агент
Мобильный агент представляет собой автономный программный агент с определенной социальной способности и , самое главное, мобильность. Он состоит из компьютерного программного обеспечения и данных, которые могут автоматически перемещаться между разными компьютерами, продолжая свою работу.
Мобильные агенты могут использоваться для согласования параллелизма и распределения, если используется вычисление соединения. Вот почему была создана новая концепция под названием «распределенное объединенное исчисление»; это расширение объединенного исчисления с местоположениями и примитивами для описания мобильности. Это нововведение использует агентов в качестве запущенных процессов с их коммуникационными возможностями, чтобы дать представление о местоположении, которое представляет собой физический сайт, выражающий фактическое положение агента. Благодаря соединению-исчислению одно место можно атомарно переместить на другое. [23]
Процессы агента задаются как набор, который определяет его функциональные возможности, включая асинхронную отправку сообщения, миграцию в другое место. Следовательно, местоположения организованы в виде дерева для более удобного представления передвижения агента. При таком представлении преимуществом этого решения является возможность создать простую модель отказа. Обычно сбой физического сайта вызывает необратимый отказ всех его местоположений. Но с исчислением соединений проблема с местоположением может быть обнаружена в любом другом рабочем месте, что позволяет исправить ошибки. [23]
Таким образом, объединенное исчисление - это ядро распределенного языка программирования. В частности, операционная семантика легко реализуется в распределенной среде с ошибками. Таким образом, распределенное исчисление соединений обрабатывает имена каналов и имена местоположений как значения первого класса с лексической областью видимости. Локация контролирует свои собственные движения и может двигаться только к локации, название которой она получила. Это обеспечивает прочную основу для статического анализа и безопасной мобильности. Это завершено для выражения распределенных конфигураций. Однако при отсутствии сбоя выполнение процессов не зависит от распределения. Эта прозрачность местоположения важна для разработки мобильных агентов и очень полезна для проверки их свойств. [23]
В 2007 году вышло расширение базового исчисления соединений с помощью методов, которые делают агентов проактивными. Агенты могут наблюдать общую среду между ними. В этой среде можно определить общие переменные для всех агентов (например, службу имен для обнаружения агентов между собой). [24]
Компиляция
Языки соединения построены на основе исчисления соединений, взятого в качестве основного языка. Таким образом, все вычисления анализируются с помощью асинхронных процессов, а шаблон соединения предоставляет модель для синхронизации результата. [9]
Для этого существует два компилятора:
- Join Compiler: компилятор языка с именем "join langage". Этот язык был создан только для исчисления соединений
- Jocaml Compiler : компилятор расширения Objectif Caml, созданный для использования исчисления соединений.
Эти два компилятора работают с одной и той же системой, автоматом.
пусть A (n) | B () = P (n)и A (n) | С () = Q (п);;
Он представляет собой потребление сообщений, поступивших в завершенную модель соединения. Каждое состояние - это возможный шаг для выполнения кода, а каждый переход - это получение сообщения для переключения между двумя шагами. И поэтому, когда все сообщения получены, компилятор выполняет код соединения тела, соответствующий завершенному стыку модели.
Итак, в объединенном исчислении основные значения - это имена, как в примере, A, B или C. Итак, два компилятора представляют эти значения двумя способами.
Компилятор соединения использует вектор с двумя слотами, первый для самого имени, а второй для очереди ожидающих сообщений.
Jocaml использует имя как указатель на определения. В этих определениях хранятся указатели на другие имена с полем состояния и соответствующей структурой даты по сообщению.
Фундаментальное различие заключается в том, когда выполняется процесс защиты: в первом случае проверялось, все ли имена готовы к ожидающим сообщениям, тогда как во втором случае используется только одна переменная и осуществляется доступ к другим, чтобы узнать, завершена ли модель. [9]
Недавние исследования описывают схему компиляции как комбинацию двух основных этапов: отправки и пересылки. Дизайн и правильность диспетчера по существу проистекают из теории сопоставления с образцом, в то время как включение шага внутренней пересылки в сообщения - естественная идея, которая интуитивно не меняет поведение процесса. Они отметили, что стоит обратить внимание на прямую реализацию расширенного сопоставления шаблонов соединений на уровне времени выполнения, что значительно усложнит управление очередями сообщений, которые затем необходимо будет сканировать в поисках совпадающих сообщений перед их использованием. [25]
Реализации и библиотеки
Есть много вариантов использования шаблонов соединения с разными языками. Некоторые языки используют шаблоны соединения в качестве основы своих реализаций, например, Polyphonic C # или MC #, но другие языки интегрируют шаблон соединения с помощью библиотеки, такой как Scala Joins [26] для Scala или библиотеки Joins для VB. [27] Более того, шаблон соединения используется в некоторых языках, таких как Scheme, для обновления шаблона соединения. [28]
Джерланг | CB | Присоединяется к библиотеке | Полифонический C # | Параллельный C # | Cω | Scala присоединяется | F # | Схема | Присоединяйтесь к Java | Юм | JoCaml | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Соответствие шаблонов | да | да | да | да | да | да | да | да | да | да | да | да |
Планировщик между шаблонами соединения | Да: первый матч | Да: первая / круговая система | да | да | да | да | да | да | Нет | Да: случайный | Да: первая / круговая система | Да: случайный |
Дженерики | да | N / A | да | Нет | N / A | Нет | да | да | Нет | Нет | Нет | Нет |
Переопределение | Нет | да | N / A | N / A | N / A | да | да | да | Нет | да | Нет | Нет |
Присоединяйтесь к Java
Присоединяйтесь к Java [29] - это язык, основанный на языке программирования Java, позволяющий использовать исчисление соединений. Он вводит три новых языковых конструкции:
- Методы соединения определяются двумя или более фрагментами соединения. Метод Join будет выполняться после того, как будут вызваны все фрагменты шаблона Join. Если тип возвращаемого значения является стандартным типом Java, тогда ведущий фрагмент будет блокировать вызывающего до тех пор, пока шаблон соединения не будет завершен и метод не будет выполнен. Если тип возврата имеет тип signal, то ведущий фрагмент вернется немедленно. Все завершающие фрагменты асинхронны, поэтому вызывающий объект не блокируется.
Пример:
class JoinExample { int fragment1 () & fragment2 ( int x ) { // Вернет значение x вызывающей стороне фрагмента 1 return x ; } }
- Асинхронные методы определяются с использованием типа возвращаемого сигнала. Он имеет те же характеристики, что и тип void, за исключением того, что метод вернется немедленно. Когда вызывается асинхронный метод, создается новый поток для выполнения тела метода.
Пример:
class ThreadExample { сигнальный поток ( SomeObject x ) { // Этот код будет выполняться в новом потоке } }
- Модификаторы порядка
Фрагменты соединения могут повторяться в нескольких шаблонах соединения, поэтому может быть случай, когда несколько шаблонов соединения завершаются при вызове фрагмента. Такой случай может произойти в приведенном ниже примере, если вызываются B (), C () и D (), затем A (). Последний фрагмент A () завершает три шаблона, поэтому есть три возможных метода, которые могут быть вызваны. Модификатор заказанного класса используется здесь, чтобы определить, какой метод Join будет вызываться. По умолчанию и при использовании модификатора неупорядоченного класса один из методов выбирается случайным образом. При использовании модификатора order приоритетность методов определяется в соответствии с порядком их объявления.
Пример:
класс упорядочен SimpleJoinPattern { void A () & B () { } void A () & C () { } void A () & D () { } signal D () & E () { } }
Ближайшим родственным языком является Polyphonic C # .
Джерланг
В коде Erlang синхронизация между несколькими процессами не является простой задачей. Вот почему был создан JErlang [30] , расширение Erlang , J - для соединения. Действительно, для преодоления этого ограничения был реализован JErlang, расширение Erlang, вдохновленное Join-Calculus . Особенности этого языка:
- Объединения допускают семантику первого совпадения и возможность наличия нескольких шаблонов с сохранением порядка сообщений.
операция () -> получить { ok , sum } и { val , X } и { val , Y } -> { sum , X + Y }; { ok , mult } и { val , X } и { val , Y } -> { mult , X * Y }; { ok , sub } и { val , X } и { val , Y } -> { sub , X - Y }; конец конец
- Guard обеспечивает дополнительную фильтрацию, не выражающуюся в терминах шаблонов. Ограниченное количество выражений без побочных эффектов
получить { Transaction , M } и { limit , Lower , Upper }, когда ( Lower <= M и M <= Upper ) -> commit_transaction ( M , Transaction ) end
- С помощью нелинейных шаблонов сообщения могут соответствовать нескольким соединениям
получить { get , X } и { set , X } -> { found , 2 , X } end ... получить { Pin , id } и { auth , Pin } и { commit , Id } -> perform_transaction ( Pin , Id ) конец
- распространение позволяет копировать правильные сообщения вместо их удаления.
получить prop ({ session , Id }) и { act , Action , Id } -> perform_action ( Action , Id ); { session , Id } и { logout , Id } -> logout_user ( Id ) end ... получить { Pin , id } и { auth , Pin } и { commit , Id } -> perform_transaction ( Pin , Id ) end
- Синхронные звонки
получить { accept , Pid1 } и { asynchronous , Value } и { accept , Pid2 } -> Pid1 ! { ok , Value }, Pid2 ! { ok , Value } конец
C ++
Yigong Liu написал несколько классов для шаблона соединения, включая все полезные инструменты, такие как асинхронные и синхронные каналы, аккорды и т. Д. Он интегрирован в проект Boost c ++ .
шаблон < typename V > буфер класса : общедоступное соединение { public : async < V > put ; синхронизировать < V , void > получить ; буфер () { аккорд ( получить , положить , & буфер :: chord_body ); } V chord_body ( void_t g , V p ) { return p ; } };
Этот пример показывает нам потокобезопасный буфер и очередь сообщений с базовыми операциями put и get. [31]
C #
Полифонический C #
Polyphonic C # - это расширение языка программирования C #. Он представляет новую модель параллелизма с синхронными и асинхронными (которые возвращают управление вызывающей стороне) методами и аккордами (также известными как «шаблоны синхронизации» или «шаблоны соединения»).
публичный класс Buffer { public String get () & public async put ( String s ) { return s ; } }
Это простой пример буфера. [32]
MC #
Язык MC # - это адаптация языка Polyphonic C # для параллельных распределенных вычислений.
публичный обработчик Get2 long () и канал c1 ( длинный x ) и канал c2 ( long y ) { return ( x + y ); }
Этот пример демонстрирует использование аккордов в качестве инструмента синхронизации.
Параллельный C #
Parallel C # основан на Polyphonic C #, и они добавляют некоторые новые концепции, такие как методы перемещения, функции высокого порядка.
используя Систему ; class Test13 { int Receive () & async Send ( int x ) { return x * x ; } public static void Main ( строка [] аргументы ) { Test13 t = new Test13 (); т . Отправить ( 2 ); Консоль . WriteLine ( т . Получать ()); } }
В этом примере показано, как использовать объединения. [33]
Cω
Cω добавляет новые языковые функции для поддержки параллельного программирования (на основе более ранней версии Polyphonic C # ). Библиотека параллелизма Joins для C # и других языков .NET является производной от этого проекта. [34] [35]
Масштабируемые шаблоны соединений
Это простая в использовании декларативная и масштабируемая библиотека шаблонов соединений. В отличие от библиотеки Руссо [27] у нее нет глобальной блокировки. Фактически, он работает с CAS- системой сравнения и обмена и системой сообщений Atomic. Библиотека [36] использует три улучшения для шаблона соединения:
- Сообщение о краже неиспользованных ресурсов (разрешение баржа);
- Ленивая очередь экономит как на распределении, так и потенциально на межпроцессорном взаимодействии, избегая выделения или постановки в очередь с оптимистичным быстрым путем;
- Состояние «WOKEN»: гарантирует, что заблокированный синхронный вызывающий абонент будет разбужен только один раз.
JoCaml
JoCaml - первый язык, на котором был реализован шаблон соединения. Действительно, в начале все различные реализации были скомпилированы с помощью компилятора JoCaml. Язык JoCaml - это расширение языка OCaml . Он расширяет OCaml за счет поддержки параллелизма и синхронизации, распределенного выполнения программ и динамического перемещения активных фрагментов программы во время выполнения. [37]
тип монеты = никель | Дайм и напитки = Кофе | Чай и пуговицы = BCoffee | BTea | BCancel ;;(* def определяет предложение набора шаблонов соединения * "&" в левой части = означает соединение (синхронизм канала) * "&" в правой части означает: параллельный процесс * synchronous_reply: == "reply" [x] "to" имя_канала * синхронные каналы имеют функционально-подобные типы (`a ->` b) * асинхронные каналы имеют типы (`a Join.chan) * только последний оператор в выражении шаблона rhs может быть асинхронным сообщением * 0 в позиция асинхронного сообщения означает STOP («сообщение не отправлено» в терминологии CSP). *)def put ( s ) = print_endline s ; 0 (* СТОП *) ;; (* положите: строка Join.chan *)def serve ( drink ) = соответствует напитку с кофе -> put ( "Cofee" ) | Чай -> положить ( "Чай" ) ;; (* подавать: напитки Join.chan *)def возврат ( v ) = let s = Printf . sprintf "Refund% d" v in put ( s ) ;; (* возврат: int Join.chan *)пусть new_vending служить возврат = пусть продажные ( стоимость : ИНТ ) ( кредит : INT ) = если кредит > = стоимость , то ( правда , кредит - стоимость ) еще ( ложь , кредит ) в четкости монеты ( никель ) и значение ( v ) = значение ( v + 5 ) & reply () для монеты или монеты ( Dime ) & value ( v ) = value ( v + 10 ) & reply () для монеты или кнопка ( BCoffee ) & value ( v ) = let should_serve , остаток = vend 10 v in ( если should_serve, то служить ( Coffee ), иначе 0 (* STOP *) ) и значение ( остаток ) и ответ () на кнопку или кнопка ( BTea ) & value ( v ) = let should_serve , остаток = vend 5 v in ( если should_serve, то служить ( Tea ) else 0 (* STOP *) ) и значение ( остаток ) и ответ () на кнопку или кнопка ( BCancel ) и значение ( v ) = возмещение ( v ) и значение ( 0 ) и ответ () на кнопку в значении появления ( 0 ) ; coin , button (* coin, button: int -> unit *) ;; монета , кнопка (* монета, кнопка: int -> unit *) ;; (* new_vending: drink Join.chan -> int Join.chan -> (int-> unit) * (int-> unit) *) пусть ccoin , cbutton = new_vending обслуживает возврат в ccoin ( никель ); ccoin ( никель ); ccoin ( Дайм ); Unix . сон ( 1 ); cbutton ( BCoffee ); Unix . сон ( 1 ); cbutton ( BTea ); Unix . сон ( 1 ); cbutton ( BCancel ); Unix . sleep ( 1 ) (* пусть появится последнее сообщение *) ;;
дает
КофеЧайВозврат 5
Юм
Hume [38] - это строгий , строго типизированный функциональный язык для платформ с ограниченными ресурсами, с параллелизмом, основанным на асинхронной передаче сообщений, программировании потоков данных и синтаксисе, подобном Haskell .
Юм не обеспечивает синхронный обмен сообщениями.
Он объединяет набор шаблонов соединения с общим каналом в виде блока , перечисляя все каналы в кортеже in и указывая все возможные выходы в кортеже out .
Каждый шаблон соединения в наборе должен соответствовать типу входного кортежа блока, определяя "*" для необязательных каналов, давая выражение, тип которого соответствует выходному кортежу, и отмечая "*" неподтвержденные выходы.
А провод оговорка указывает
- кортеж соответствующих входных источников или источников и, возможно, начальные значения
- кортеж выходных адресатов, являющихся каналами или приемниками (stdout, ..).
Окно можно указать обработчик исключений с выражениями , соответствующих выходными кортежа.
Данные Монеты = Никель | Дайм ; данные Напитки = Кофе | Чай ; кнопки данных = BCoffee | BTea | BCancel ; введите Int = int 32 ; тип String = строка ; показать u = u как строку ;box coffee in ( coin :: Coins , button :: Buttons , value :: Int ) - входные каналы out ( drink_outp :: String , value ' :: Int , return_outp :: String ) - именованные выходыmatch - * подстановочные знаки для незаполненных выходных и неиспользованных входов ( Nickel , * , v ) -> ( * , v + 5 , * ) | ( Дайм , * , v ) -> ( * , v + 10 , * ) | ( * , BCoffee , v ) -> продавец Кофе 10 v | ( * , BTea , v ) -> продавать чай 5 v | ( * , BCancel , v ) -> пусть возврат u = "Refund" ++ покажет u ++ " \ n " в ( * , 0 , return v ) ;продажная напиток стоимость кредитного = если кредит > = стоимость затем ( служить напиток , кредитного - стоимость , * ) еще ( * , кредит , * );служить напиток = случай напиток из кофе -> «Кофейные \ п » Чай -> «Чай \ п » ;box control in ( c :: char ) out ( coin :: Coins , button :: Buttons ) соответствует 'n' -> ( Nickel , * ) | 'd' -> ( Дайм , * ) | 'c' -> ( * , BCoffee ) | 't' -> ( * , BTea ) | 'x' -> ( * , BCancel ) | _ -> ( * , * ) ;поток console_outp в "std_out" ; поток console_inp из "std_in" ;- проводка потока данных wire cofee - входы (источники канала) ( control . coin , control . button , coffee . value ' изначально 0 ) - выходы назначения ( console_outp , coffee . value , console_outp ) ; проводное управление ( console_inp ) ( кофе . монета , кофе . кнопка ) ;
Visual Basic
Параллельный базовый - CB
Расширение Visual Basic 9.0 с конструкциями асинхронного параллелизма, называемое Concurrent Basic (сокращенно CB), предлагает шаблоны соединения. CB (основанный на более ранней работе над Polyphonic C #, Cω и библиотекой Joins) использует простой синтаксис, подобный событиям, знакомый программистам VB, позволяет объявлять общие абстракции параллелизма и обеспечивает более естественную поддержку наследования, позволяя подклассу расширять набор шаблонов. Класс CB может объявить метод для выполнения, когда связь произошла по определенному набору локальных каналов, асинхронных и синхронных, образуя шаблон соединения. [27]
Модуль Buffer Public Asynchronous Put ( ByVal s As String ) Открытый синхронный Take () As String Private Function CaseTakeAndPut ( ByVal сек Как строка ) Как строки _ Если принять , Помещенный Return сек End FunctionКонечный модуль
В этом примере показаны все новые ключевые слова, используемые Concurrent Basic: Asynchronous, Synchronous и When. [39]
Библиотека объединений (C # и VB)
Эта библиотека представляет собой высокоуровневую абстракцию шаблона соединения с использованием объектов и универсальных шаблонов. Каналы - это специальные значения делегатов от некоторого общего объекта Join (вместо методов). [40]
class Buffer { общедоступный только для чтения Асинхронный . Канал < строка > Положить ; public readonly Synchronous < строка >. Channel Get ; public Buffer () { Присоединиться, присоединиться = Присоединиться . Создать (); присоединиться . Инициализировать ( Out Put ); присоединиться . Initialize ( из Get ); присоединиться . Когда ( Получить ). И ( Положите ). Сделать ( делегат ( строка s ) { return s ; }); } }
В этом примере показано, как использовать методы объекта Join. [41]
Scala
В Scala есть библиотека под названием «Scala Joins» Scala Joins для использования Join-Pattern, она предлагает использовать сопоставление с образцом Сопоставление с образцом в качестве инструмента для создания моделей объединений. Вы можете найти примеры использования шаблона соединения в scala здесь: Определения соединения в Scala .
Средства сопоставления с образцом этого языка были обобщены, чтобы обеспечить независимость представления для объектов, используемых при сопоставлении с образцом. Итак, теперь в библиотеках можно использовать новый тип абстракции. Преимущество шаблонов соединения состоит в том, что они позволяют декларативно определять синхронизацию между различными потоками. Часто шаблоны соединения близко соответствуют конечному автомату, который определяет допустимые состояния объекта.
В Scala можно решить многие проблемы с сопоставлением с образцом и объединениями Scala, например Reader-Writer. [26]
class ReaderWriterLock extends Joins { private val Sharing = new AsyncEvent [ Int ] val Exclusive , ReleaseExclusive = new NullarySyncEvent val Shared , ReleaseShared = new NullarySyncEvent join { case Exclusive () & Sharing ( 0 ) => Эксклюзивный ответ case ReleaseExclusive () => { Sharing ( 0 ); ReleaseExclusive reply } case Shared () & Совместное использование ( n ) => { Совместное использование ( n + 1 ); Общий ответ } case ReleaseShared () & Sharing ( 1 ) => { Sharing ( 0 ); ReleaseShared reply } case ReleaseShared () & Совместное использование ( n ) => { Совместное использование ( n - 1 ); ReleaseShared reply } } Отправка ( 0 ) }
С помощью класса мы объявляем события в обычных полях. Таким образом, можно использовать конструкцию Join, чтобы включить сопоставление с образцом через список объявлений case. Этот список обозначается знаком => с частями объявления на каждой стороне. Слева представлена модель шаблона соединения, чтобы показать комбинацию асинхронных и синхронных событий, а справа - тело соединения, которое выполняется с завершенной моделью соединения.
В Scala также можно использовать библиотеку акторов Scala [42] с шаблоном соединения. Например, неограниченный буфер: [26]
val Put = new Join1 [ Int ] val Get = new Join class Buffer extends JoinActor { def act () { receive { case Get () & Put ( x ) => Get reply x } } }
Параллелизм на основе акторов поддерживается посредством библиотеки, и мы также предоставляем шаблоны соединений в качестве расширения библиотеки, поэтому есть возможность комбинировать шаблоны соединений с управляемой событиями моделью параллелизма, предлагаемой субъектами. Как вы видите в примере, это тот же способ использования шаблона соединения с акторами, он просто делает это список объявления case в методе receive, чтобы показать, когда модель будет завершена.
Практически те же инструменты доступны в F # для использования шаблона соединения.
Scala Join и Chymyst - это более новые реализации шаблона Join, улучшенные по сравнению с Scala Joins доктора Филиппа Халлера .
Haskell
Язык соединения - это реализация шаблона соединения в Haskell.
Схема
Шаблоны соединения позволяют использовать новый тип программирования, особенно для многоядерных архитектур, доступных во многих ситуациях программирования с высокими уровнями абстракции. Это основано на Стражах и Распространении. Итак, пример этого нововведения был реализован в Scheme. [28]
Защита необходима для гарантии того, что обновляются / извлекаются только данные с совпадающим ключом. Распространение может отменить элемент, прочитать его содержимое и вернуть элемент в магазин. Конечно, во время чтения товар тоже находится в магазине. Охранники выражаются общими переменными. Итак, новинка состоит в том, что шаблон соединения теперь может содержать расширенные и упрощенные части. Итак, в схеме часть до / распространяется, а часть после / удаляется. Использование цели на основе состоит в том, чтобы разделить работу на множество задач и объединить все результаты в конце с шаблоном соединения. Система под названием «MiniJoin» реализована для использования промежуточного результата для решения других задач, если это возможно. Если это невозможно, он ждет решения других задач, чтобы решить сам.
Таким образом, приложение шаблона параллельного соединения, выполняемое параллельно в многоядерной архитектуре, не гарантирует, что параллельное выполнение приведет к конфликтам. Чтобы гарантировать это и высокую степень параллелизма, используется программная транзакционная память (STM) в хорошо настроенной параллельной структуре данных, основанной на атомарном сравнении и обмене (CAS). Это позволяет выполнять множество одновременных операций параллельно в многоядерной архитектуре. Более того, атомарное выполнение используется для предотвращения «ложного конфликта» между CAS и STM. [28]
Другие похожие шаблоны проектирования
Шаблон соединения - не единственный шаблон для выполнения многозадачности, но он единственный, который разрешает обмен данными между ресурсами, синхронизацию и присоединение к различным процессам.
- Шаблон последовательности: состоит из ожидания завершения одной задачи, чтобы переключиться на другую (классическая реализация). [43]
- Шаблон разделения ( параллельное разделение ): одновременное выполнение нескольких задач (например, уменьшение карты ). [44]
Смотрите также
- Присоединяйтесь к Java - Присоединяйтесь к Java - это язык программирования, расширяющий стандартный язык программирования Java.
- Joins (библиотека параллелизма) - Joins - это API асинхронных параллельных вычислений от Microsoft Research для .NET Framework.
- Объединенное исчисление - объединенное исчисление было разработано, чтобы обеспечить формальную основу для проектирования распределенных языков программирования.
Рекомендации
- Седрик, Фурне; Люк, Маранге (15 августа 2006 г.). «Язык объединенного исчисления» . Национальный институт научных исследований в области информатики и автоматизации . Проверено 9 октября 2012 .
- «JoinCalculus» . Cunningham & Cunningham, Inc. 25 октября 2009 . Проверено 9 октября 2012 .
- Фурне, Седрик; Гонтье, Жорж; Леви, Жан-Жак; Маранге, Люк (1996). CONCUR '96: Теория параллелизма . Конспект лекций по информатике. 1119 . Ле Шене: теория параллелизма. С. 406–421. DOI : 10.1007 / 3-540-61604-7_67 . ISBN 978-3-540-61604-7.
- Малудзинский, Славомир; Добровольский, Гжегож (2007). Среда агента и знания в распределенном исчислении соединений . Конспект лекций по информатике . 4696 . С. 298–300. DOI : 10.1007 / 978-3-540-75254-7_30 . ISBN 978-3-540-75253-0.
- Руссио, Клаудио (2007). «Библиотека параллелизма Joins». Практические аспекты декларативных языков . Конспект лекций по информатике. 4354 . Кембридж: Практические аспекты декларативных языков. С. 260–274. CiteSeerX 10.1.1.187.8792 . DOI : 10.1007 / 978-3-540-69611-7_17 . ISBN 978-3-540-69608-7.
- Маранге, Люк; Ле Фессан, Фабрис (25 сентября 2007 г.). «Составление шаблонов соединений» . Ле Шене Франция. Цитировать журнал требует
|journal=
( помощь ) - Галлер, Филипп; Ван Катсем, Том (2008). Координационные модели и языки . Конспект лекций по информатике. 5052 . Лозанна: координационные модели и языки. С. 1–15. CiteSeerX 10.1.1.210.1242 . DOI : 10.1007 / 978-3-540-68265-3_9 . ISBN 978-3-540-68264-6.
- Зульцманн, Мартин; SL Лам, Эдмунд. «Образцы параллельного соединения с охранниками и размножением» . Дания. Цитировать журнал требует
|journal=
( помощь ) - Фурне, Седрик; Гонтье, Жорж (2002). Прикладная семантика . Конспект лекций по информатике. 2395 . Каминья. С. 1–66. CiteSeerX 10.1.1.4.4788 . DOI : 10.1007 / 3-540-45699-6_6 . ISBN 978-3-540-44044-4.
- Ма, Цинь; Маранге, Люк (5 апреля 2004 г.). КОНКУР 2004 - Теория параллелизма . Конспект лекций по информатике. 3170 . INRIA. С. 417–431. CiteSeerX 10.1.1.499.8443 . DOI : 10.1007 / 978-3-540-28644-8_27 . ISBN 978-3-540-22940-7.
- Сингх, Сатнам (6 января 2007 г.). «Комбинаторы высшего порядка для шаблонов соединения с использованием STM» . Цитировать журнал требует
|journal=
( помощь ) - МОНСЬЕР, Герт (2010), Координация на основе шаблонов в сервисных композициях на основе процессов , Лёвен, Бельгия: Katholiek Universiteit Leuven
- Руссо, Клаудио В. (23 октября 2008 г.). «Шаблоны соединения для Visual Basic». Уведомления ACM SIGPLAN . 43 (10): 53–72. DOI : 10.1145 / 1449955.1449770 .
- Аарон, Турон; Руссо, Клаудио В. (27 октября 2011 г.). Масштабируемые шаблоны соединений (PDF) . Портленд, Орегон, США. ISBN 9781450309400.
- Гузев, Вадим Б. (апрель 2008 г.). «Параллельный C #: использование аккордов и функций высшего порядка в разработке языков параллельного программирования» (PDF) . Москва, Россия. Цитировать журнал требует
|journal=
( помощь )
Заметки
- ^ Таральский дракон (25 октября 2009 г.). «Присоединиться к исчислению» . Проверено 2012 . Проверить значения даты в:
|access-date=
( помощь ) - ^ Руссо, Клаудио В. (23 октября 2008 г.). «Шаблоны соединения для Visual Basic». Уведомления ACM SIGPLAN . 43 (10): 10. DOI : 10,1145 / 1449955,1449770 .
- ^ «Параллельный C #» . Проверено 2012 . Проверить значения даты в:
|access-date=
( помощь ) - ^ Руссо, Клаудио В. "Шаблоны соединения для Visual Basic": 2. Цитировать журнал требует
|journal=
( помощь ) - ^ Фурне, Седрик; Гонтье, Жорж (2002). Прикладная семантика . Конспект лекций по информатике. 2395 . Каминья. С. 268–332. CiteSeerX 10.1.1.4.4788 . DOI : 10.1007 / 3-540-45699-6_6 . ISBN 978-3-540-44044-4.
- ^ a b c d e f Шаблоны соединения для Visual Basic и Клаудио В. Руссо .
- ^ Руссо, Клаудио В. (23 октября 2008 г.). «Шаблоны соединения для Visual Basic». Уведомления ACM SIGPLAN . 43 (10): 5. DOI : 10,1145 / 1449955,1449770 .
- ^ Руссо, Клаудио В. (23 октября 2008 г.). «Шаблоны соединения для Visual Basic». Уведомления ACM SIGPLAN . 43 (10): 18. DOI : 10,1145 / 1449955,1449770 .
- ^ а б в Маранге, Люк; Ле Фессан, Фабрис (25 сентября 2007 г.). «Составление шаблонов соединений» . Ле Шене Франция. Цитировать журнал требует
|journal=
( помощь ) - ^ Фурне, Седрик; Гонтье, Жорж; Леви, Жан-Жак; Маранге, Люк (1996). CONCUR '96: Теория параллелизма . Конспект лекций по информатике. 1119 . Ле Шене: теория параллелизма. С. 406–421. DOI : 10.1007 / 3-540-61604-7_67 . ISBN 978-3-540-61604-7.
- ^ Фурне, Седрик; Ле Фессан, Фабрис; Маранге, Люк; Шмитт, А. (сентябрь 2000 г.). «JoCaml: язык для параллельного распределенного и мобильного программирования». В Advanced Functional Programming, 4 - я Международная SchoolOxford, август 2002 . 2638 .
- ^ Conchon, S .; Ле Фессан, Ф. (1999). «JoCaml: мобильные агенты для Objective-Caml». В Первом международном симпозиуме по агентским системам и приложениям. (ASA'99) / Третий международный симпозиум по мобильным агентам (MA'99) .
- ^ Одерский, Мартин (сентябрь 2000 г.). «Обзор функциональных сетей». Летняя школа, Caminha, Португалия, сентябрь 2000 . 2395 .
- ^ Одерский, Мартин (2000). «Функциональные сети». В материалах Европейского симпозиума по программированию. Конспект лекций по информатике . Конспект лекций по информатике. 1782 : 1-25. DOI : 10.1007 / 3-540-46425-5_1 . ISBN 978-3-540-67262-3.
- ^ Itzstein, GS; Кирни, Д. (2001). «Присоединяйтесь к Java: альтернативная семантика параллелизма для Java». Технический отчет ACRC-01-001, Университет Южной Австралии .
- ^ Benton, N .; Фурнет, К. (июнь 2002 г.). «Современные абстракции параллелизма для C #». В трудах 16-й Европейской конференции по объектно-ориентированному программированию (ECOOP 2002), номер 2374 в LNCS .
- ^ Benton, N .; Карделли, Л. (2004). «Современные абстракции параллелизма для C #. Транзакции ACM на языках программирования и системах». 26 . Цитировать журнал требует
|journal=
( помощь ) - ^ Сингх, Сатнам (6 января 2007 г.). «Комбинаторы высшего порядка для шаблонов соединения с использованием STM» : 1. Цитировать журнал требует
|journal=
( помощь ) - ^ а б Аарон, Турон; Руссо, Клаудио В. (27 октября 2011 г.). Масштабируемые шаблоны соединений (PDF) . Портленд, Орегон, США. п. 4. ISBN 9781450309400.
- ^ Аарон, Турон; Руссо, Клаудио В. (27 октября 2011 г.). Масштабируемые шаблоны соединений (PDF) . Портленд, Орегон, США. п. 1. ISBN 9781450309400.
- ^ а б Аарон, Турон; Руссо, Клаудио В. (27 октября 2011 г.). Масштабируемые шаблоны соединений (PDF) . Портленд, Орегон, США. п. 3. ISBN 9781450309400.
- ^ Аарон, Турон; Руссо, Клаудио В. (27 октября 2011 г.). Масштабируемые шаблоны соединений (PDF) . Портленд, Орегон, США. п. 2. ISBN 9781450309400.
- ^ а б в Фурне, Седрик; Гонтье, Жорж; Леви, Жан-Жак; Маранге, Люк; Реми, Дидье (1996). CONCUR '96: Теория параллелизма . Конспект лекций по информатике. 1119 . Ле Шене: теория параллелизма. С. 406–421. DOI : 10.1007 / 3-540-61604-7_67 . ISBN 978-3-540-61604-7.
- ^ Малудзинский, Славомир; Добровольский, Гжегож (2007). «Среда агента и знания в распределенном исчислении соединений». Multi-Agent системы и приложения V . Конспект лекций по информатике. 4696 . С. 298–300. DOI : 10.1007 / 978-3-540-75254-7_30 . ISBN 978-3-540-75253-0.
- ^ Ма, Цинь; Маранге, Люк (5 апреля 2004 г.). КОНКУР 2004 - Теория параллелизма . Конспект лекций по информатике. 3170 . INRIA. С. 417–431. CiteSeerX 10.1.1.499.8443 . DOI : 10.1007 / 978-3-540-28644-8_27 . ISBN 978-3-540-22940-7.
- ^ а б в Галлер, Филипп; Ван Катсем, Том (2008). Координационные модели и языки . Конспект лекций по информатике. 5052 . Лозанна: координационные модели и языки. С. 1–15. CiteSeerX 10.1.1.210.1242 . DOI : 10.1007 / 978-3-540-68265-3_9 . ISBN 978-3-540-68264-6.
- ^ а б в Руссо, Клаудио В. (23 октября 2008 г.). «Шаблоны соединения для Visual Basic». Уведомления ACM SIGPLAN . 43 (10): 53–72. DOI : 10.1145 / 1449955.1449770 .
- ^ а б в Зульцманн, Мартин; SL Лам, Эдмунд. «Образцы параллельного соединения с охранниками и размножением» . Дания. Цитировать журнал требует
|journal=
( помощь ) - ^ Hopf, J .; von Itzstein, G .; Стюарт и др. (2002). «Оборудование присоединяется к Java: язык высокого уровня для разработки реконфигурируемого оборудования» . Гонконг. Архивировано из оригинала на 2013-02-19. Цитировать журнал требует
|journal=
( помощь ) - ^ Плоциничак, Губерт; Айзенбах, Сьюзен (2009). «JErlang: Erlang с объединениями» (PDF) . Конспект лекций по информатике . Лондон. 6116 : 61–75. Bibcode : 2010LNCS.6116 ... 61P . DOI : 10.1007 / 978-3-642-13414-2_5 . ISBN 978-3-642-13413-5. Архивировано из оригинального (PDF) 10.10.2017 . Проверено 10 декабря 2012 .
- ^ Лю, Игун (2007–2009). «Присоединиться - асинхронная библиотека координации сообщений и параллелизма» . Проверено 2012 . Проверить значения даты в:
|access-date=
( помощь ) - ^ «Введение в полифонический C #» . Проверено 2012 . Проверить значения даты в:
|access-date=
( помощь ) - ^ «Параллельный C #» . Архивировано из оригинала на 2013-11-26 . Проверено 2012 . Проверить значения даты в:
|access-date=
( помощь ) - ^ Ханус, Майкл (январь 2007 г.). Библиотека параллелизма Joins . 4354 . ISBN 9783540696087. Проверено 2012 . Проверить значения даты в:
|access-date=
( помощь ) - ^ «Комега» . Проверено 2012 . Проверить значения даты в:
|access-date=
( помощь ) - ^ Аарон, Турон; Руссо, Клаудио В. (27 октября 2011 г.). Масштабируемые шаблоны соединений (PDF) . Портленд, Орегон, США. ISBN 9781450309400.
- ^ Фурне, Седрик; Ле Фессан, Фабрис; Маранге, Люк; Шмитт, Алан (2003). «JoCaml: язык для параллельного распределенного и мобильного программирования» (PDF) . Расширенное функциональное программирование . Конспект лекций по информатике. Springer-Verlag. С. 129–158.
- ^ Хаммонд / Майклсон / Солнце - Программирование реактивных систем в Юме
- ^ «Параллельный базовый» . Архивировано из оригинала на 2015-04-25 . Проверено 2012 . Проверить значения даты в:
|access-date=
( помощь ) - ^ Руссио, Клаудио (2007). «Библиотека параллелизма Joins». Практические аспекты декларативных языков . Конспект лекций по информатике. 4354 . Кембридж: Практические аспекты декларативных языков. С. 260–274. CiteSeerX 10.1.1.187.8792 . DOI : 10.1007 / 978-3-540-69611-7_17 . ISBN 978-3-540-69608-7.
- ^ «Библиотека параллелизма Joins» . Проверено 2012 . Проверить значения даты в:
|access-date=
( помощь ) - ^ Галлер, Филипп; Одерский, Мартин (июнь 2007 г.). «Актеры, объединяющие темы и события». В Proc. Координация, LNCS. Цитировать журнал требует
|journal=
( помощь ) - ^ МОНСЬЕР, Герт (2010), Координация на основе шаблонов в составе услуг на основе процессов , Лёвен, Бельгия: Katholiek Universiteit Leuven, стр. 68
- ^ МОНСЬЕР, Герт (2010), Координация на основе шаблонов в составе услуг на основе процессов , Лёвен, Бельгия: Katholiek Universiteit Leuven, стр. 70
Внешние ссылки
- Параллельный базовый
- Масштабируемые объединения
- Библиотека параллелизма Joins
- INRIA, Присоединяйтесь к домашней странице Calculus