Параллельное программирование - не самое простое занятие, и, возможно, не самая простая концепция для новичка или даже для опытного программиста, чтобы эффективно применить ее к реальным проблемам.

В языке программирования Ballerina мы сделали написание параллельных программ настолько естественным, насколько это возможно. Нет никаких специальных библиотек, которые вам нужно импортировать, или каких-либо сложных концепций, о которых вам нужно знать, чтобы работать продуктивно. Корни Балерины уходят корнями в самый естественный подход, который люди используют для моделирования проблем, - это диаграммы последовательности. В любом случае, когда нам нужно объяснить кому-то проблему и решение, мы можем легко нарисовать диаграмму последовательности, чтобы показать все возможные взаимодействия и пути выполнения программы. Он содержит изначально поддерживаемый режим параллелизма с использованием линий жизни в диаграммах последовательности.

Изображение выше представляет собой реальный редактируемый вид программы, доступной в Ballerina Composer. Эта конкретная программа содержит двух параллельных рабочих процессов, которые выполняют свою собственную независимую обработку и используют синтаксический анализ сообщений для согласования поведения друг с другом. Лучшая часть Ballerina заключается в том, что все языковые конструкции также совместимы с графическим моделированием; так что редактирование вашей программы в графическом или текстовом режиме становится простым процессом. Эта функциональность особенно выделяется, когда речь идет о поддерживаемых конструкциях параллельного программирования.

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

Приведенный выше код определяет основную функцию с двумя определенными в ней рабочими. Эти рабочие будут выполняться одновременно при вызове функции. Если вы не определите явного воркера с помощью блока «worker», содержимое функции будет использовано для создания единственного неявного воркера для функции. Синтаксический анализ сообщений между рабочими процессами выполняется с помощью инструкций отправки и получения рабочего, которые в основном состоят из формата «переменная -› имя_работника »и« имя_работника ‹- переменная» соответственно. В листинге 02 ниже показано текстовое представление программы, показанной на рисунке 01.

Синтаксический анализ сообщений между рабочими процессами выполняется таким образом, что каждая «отправка рабочего» должна содержать соответствующий «рабочий прием» в принимающем работнике в том же порядке. Это необходимо для того, чтобы убедиться, что всегда есть подходящая пара отправки / получения, и чтобы избежать возможности взаимоблокировок.

Вам может быть интересно, если у нас несколько рабочих, можем ли мы вернуться и от нескольких рабочих, и когда вызов функции действительно завершается, если есть несколько рабочих, и только один возвращается? Ответ таков: у вас может быть несколько воркеров, имеющих код с операторами возврата, но во время выполнения только один воркер может фактически выполнить оператор возврата. В момент выполнения return от рабочего процесса функция возвращается вызывающей стороне с этим результатом, а затем остальные рабочие все еще могут продолжать выполнение до своего завершения, но они не могут снова выполнить оператор return, если он выполнен таким образом, среда выполнения регистрирует сообщение об ошибке. Кроме того, в случае функции void по умолчанию она будет ждать, пока все рабочие завершат ее выполнение, прежде чем функция вернется к вызывающему, иначе рабочий может явно выполнить пустой оператор «return», чтобы немедленно вернуться к звонящий.

Вилка / Присоединение

Fork / Join - это конструкция в Ballerina, когда вы хотите разделить текущее выполнение в середине функции, которая будет выполняться одновременно. Это будет в основном fork для выполнения нескольких рабочих процессов, и эти рабочие процессы будут выполняться независимо, и в соответствии с определенным правилом соединения, он будет ждать завершения рабочих процессов и отправлять свои результаты в соединение. блок. Правила присоединения содержат такие параметры, как ожидание завершения всех воркеров или ожидание определенного количества воркеров, определенный набор имен воркеров или иначе, дождаться определенного тайм-аута, указанного пользователем.

Пример вилки / соединения можно найти ниже:

В листинге 03 показан сценарий обработки заказа, в котором подпроцессы проверки запасов и проверки кредитоспособности выполняются параллельно, а результаты позже объединяются для получения окончательного результата.

Асинхронные функции

Возможно, у вас есть требование, при котором вы не знаете, сколько воркеров вам понадобится, то есть вам нужно динамически создавать новых воркеров для выполнения в фоновом режиме, или же вам нужно запустить существующую функцию в фон. Здесь в игру вступает асинхронный вызов функции Ballerina. Здесь любой вызов функции или действия, который у вас может быть, когда вы вызываете функцию, вы можете сигнализировать среде выполнения, чтобы запустить ее как асинхронный вызов. Это делается с помощью префикса вызова функции с помощью ключевого слова «start». В этот момент вызов функции немедленно вернется, и рабочие внутри целевой функции будут выполняться в фоновом режиме. Пример асинхронного вызова можно увидеть ниже в листинге 04.

При каждом вызове асинхронной функции он немедленно возвращает объект «будущего». Этот будущий объект можно использовать для получения результата вызова целевой функции с помощью инструкции await, или же он также может управлять такими операциями, как «isDone», «isCancelled», «cancel». , чтобы проверить текущий статус асинхронного вызова или отменить его, если это необходимо.

В асинхронных вызовах, когда вы выполняете «await ‹future_object›», это имеет то же поведение, что и обычный вызов функции, и ожидание результата. То есть в успешном сценарии он в конечном итоге вернет значение результата целевой функции, иначе, если он выдаст ошибку, оператор await также выдаст ту же самую ошибку вызывающему. Таким образом, асинхронный вызов можно легко адаптировать к вашему коду, без необходимости учитывать какие-либо другие сложности.

Балерина ВМ Рабочий Планировщик

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

Кроме того, модель программирования Ballerina реализована таким образом, что пользователю не нужно задумываться об этих деталях, а, скорее, это автоматически выполняется самой системой. Например, когда вы выполняете операцию, связанную с сетью, такую ​​как HTTP-вызов, он по умолчанию будет использовать неблокирующий ввод-вывод и освободить текущего рабочего, когда вызов будет выполнен, а текущий выполняющийся рабочий будет разбужен, когда ответ возвращается вызывающему абоненту. Следующий пример кода демонстрирует это.

В приведенном выше коде, когда на конечной точке вызывается действие «получить», рабочий выполняет неблокирующий вызов, и рабочий переходит в неактивное состояние, и его поддерживающий поток ОС будет освобожден. Таким образом, это гарантирует, что мы не будем тратить впустую потоки ОС из-за сетевых операций и т. Д., Что позволяет программам Ballerina использовать процессор наиболее оптимальным образом. Кроме того, эта модель программирования значительно упрощает жизнь разработчика, поскольку ему не нужно думать об отдельных обратных вызовах и т. Д. Для обработки ответа на неблокирующие вызовы и подобных сценариев. По сути, эта сложность скрыта от пользователей в Ballerina и позволяет использовать чистую модель программирования.

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