Статьи

Свидание: метод параллелизма в JR

В этом посте мы увидим новую функцию JR: рандеву.

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

Свидание может упростить этот вид операций:

int x;
int y;
send op_command(2, 3);
receive(x, y);

Чтобы сделать рандеву, мы используем оператор ввода. Я думаю, что это более сложное (но и наиболее полное) утверждение языка программирования JR. Вот общая форма:

inni op_command {
//Code block
}
[] op_command {
//Code block
}...

Команда op_command указывает операцию, которую нужно ждать. Команда op имеет следующую форму:

return_type op_exp(args) st synch by sched

Пояснения:

  • return_type: укажите тип возврата ожидаемой операции
  • op_exp: имя операции или возможности
  • args: аргументы операции
  • St Synch: добавить условие для операций. Это условие указывает, какие сообщения являются приемлемыми
  • по расписанию: укажите порядок обслуживания сообщений. Должен быть числовым. Сообщение с наименьшим значением выражения планирования будет обслуживаться первым.

Если нет выражения синхронизации и выражения планирования, первый обслуживаемый вызов является самым старым. Если есть выражение синхронизации, первый обслуживаемый вызов является самым старым выбираемым выражением, а если есть выражение планирования, то первый обслуживаемый является первым выбираемым вызовом, который минимизирует выражение планирования. Если нет выбираемого сообщения, оператор ввода задерживается до его появления.

Вы также можете добавить оператор else к оператору ввода:

inni op_command {
//Code block
} ...
[] else {
//Code block
}

Блок else будет выполнен, если нет выбираемого сообщения. Поэтому оператор ввода с оператором else никогда не будет задерживаться.

Давайте представим простой пример. Сервер возвращает сумму 2 чисел после получения сообщения. Если мы напишем эту простую программу с использованием асинхронного сообщения, это даст нам что-то вроде:

public class Calculator {
private static op void request(int x, int y);
private static op void response(int sum, int sub);

public static void main(String... args){}

private static process Client {
send request(33, 22);

int sum;
int sub;
receive response(sum, sub);

System.out.printf("Sum %d Sub %d", sum, sub);
}

private static process Server {
int x;
int y;
receive request(x, y);
send response(x + y, x - y);
}
}

Это немного сложно для такой простой вещи, не так ли? Давайте перепишем его с помощью оператора ввода:

public class CalculatorInni {
private static op int compute(int x, int y);

public static void main(String... args){}

private static process Client {
System.out.printf("Sum %d", compute(33, 22));
}

private static process Server {
inni int compute(int x, int y){
return x + y;
}
}
}

Проще, короче и понятнее, не так ли?

Клиент вызывает операцию вычисления и получает возвращаемое значение напрямую, потому что это синхронно. Если у вас есть операция с возвращаемым значением, вам не нужно использовать оператор вызова, это неявно. Если у вас есть операция void, вы можете использовать оператор вызова (но если вы этого не сделаете, он по умолчанию тот же) перед операцией:

call op_command(args);

Сервер должен использовать только оператор ввода для возврата суммы чисел.

Как вы, возможно, видели, получение — это только аббревиатура от самой простой формы оператора ввода. Так что если вы напишите:

int x;
int y;
receive op_command(x, y);

Это так же, как если бы вы написали:

inni void op_command(int a, int b){
x = a;
y = b;
}

Но в этом случае проще использовать оператор получения.

Оператор ввода также может использоваться для обслуживания группы операций в массиве:

cap void (int) operations = new cap void (int)[12];
//Fill the array

inni ((int i = 0; i < 12; i++)) operations[i](int x) {
//Code block
}

Помимо возврата, мы могли бы также использовать два новых оператора в операторе ввода:

  • reply: возвращает значение вызывающей стороне, но не прерывает оператор ввода, поэтому вы все еще можете выполнять операции в операторе ввода, но больше не можете возвращать значение.
  • вперед: делегировать ответ другой операции. Так что это другая операция, которая будет отвечать вызывающей стороне, оператор ввода продолжает выполнение, но больше не может возвращать значение.

Теперь, когда мы знаем, как использовать оператор ввода, мы можем упростить ResourceAllocator следующего поста. Мы можем сделать намного проще, используя две операции и операторы ввода:

import java.util.*;

public class ResourceAllocator {
private static final int N = 25; //Number of clients
private static final int I = 25; //Number of iterations

public static void main(String... args){}

private static op Resource request();
private static op void release(Resource);

private static process Client((int i = 0; i < N; i++)){
for(int a = 0; a < I; a++){
Resource resource = request();

System.out.printf("Client %d use resource %d \n", i, resource.getId());

call release(resource);
}
}

private static process Server{
Queue resources = new LinkedList();

for(int i = 1; i <= 5; i++){
resources.add(new Resource(i));
}

while(true){
inni Resource request() st !resources.isEmpty() {
return resources.poll();
}
[] void release(Resource resource){
resources.add(resource);
}
}
}

private static final class Resource {
private final int id;

private Resource(int id){
super();

this.id = id;
}

private int getId(){
return id;
}
}
}

Яснее? Последнее улучшение, которое мы можем сделать, — это использовать отправку вместо звонка в клиенте. Нам не нужно ждать освобождения в клиенте, и оператор ввода может обслуживать как вызовы отправки, так и вызовы, но вызовы отправки не могут возвращать что-либо.

Итак, теперь мы рассмотрели систему синхронизации рандеву в системе JR. В следующем и последнем посте о языке программирования JR мы увидим, как распределить наши процессы по нескольким виртуальным машинам.

С http://www.baptiste-wicht.com/2010/07/rendezvous-concurrency-jr/