# ...

Поэтому сервер выглядит так:

require 'rinda/tuplespace'

ts = Rinda::TupleSpace.new

DRb.start_service('druby://somehost:9000', ts)

gets # Нажать Enter для завершения сервера.

А клиент — так:

require 'rinda/tuplespace'

DRb.start_service

ts = DRbObject.new(nil, 'druby://somehost:9000')

# ...

К пространству кортежей в Rinda применимы пять операций: read, read_all, write, take и notify.

Операция чтения read позволяет получить один кортеж. Но способ идентификации кортежа не вполне очевиден: необходимо задать кортеж, соответствующий искомому; при этом nil соответствует любому значению.

t1 = ts.read [:Sum,nil] # Может извлечь, например, [:Sum, 14].

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

t2 = ts.read [:Result,nil],0 # Возбуждает исключение, если кортеж

# не существует.

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

tuples = ts.read_all [:Foo, nil, nil]

tuples.each do |t|

# ...

end

Метод read_all не принимает второго параметра. Он всегда блокирует программу, если не найдено ни одного подходящего кортежа.

Операция take — это чтение, за которым следует удаление. Иными словами, метод take удаляет кортеж из пространства кортежей и возвращает его вызывающей программе:

t = ts.take [:Sum, nil] # Кортежа больше нет в пространстве кортежей.

Может возникнуть вопрос, почему не существует явного способа удаления. Надо полагать, что этой цели служит метод take.

Метод write помещает кортеж в пространство кортежей. Второй параметр показывает, сколько секунд кортеж может существовать, прежде чем система сочтет, что срок его хранения истек. (По умолчанию его значение равно nil, то есть срок хранения не ограничен.)

ts.write [:Add, 5, 9]      # Хранить 'вечно'.

ts.write [:Foo, 'Bar'], 10 # Хранить 10 секунд.

Здесь уместно будет сказать несколько слов о синхронизации. Предположим, что два клиента пытаются одновременно забрать (take) один и тот же кортеж. Одному это удастся, а другой будет заблокирован. Если первый клиент затем изменит кортеж и запишет (write) его обратно в хранилище, то второй получит модифицированную версию. Можно считать, что операция «обновления» — это последовательность take и write, которая не приводит к потере данных. Конечно, как и при любом варианте многопоточного программирования, нужно позаботиться о том, чтобы не возникали тупиковые ситуации.

Метод notify позволяет следить за пространством кортежей и получать уведомления, когда над интересующим вас кортежем была выполнена какая-то операция. Этот метод возвращает объект NotifyTemplateEntry и может наблюдать на операциями четырех видов:

• write;

• take;

• удаление (когда истекает срок хранения кортежа);

• закрытие (когда истекает срок хранения объекта NotifyTemplateEntry).

Поскольку операция чтения ничего не изменяет, то система не поддерживает уведомлений о чтениях. В листинге 20.4 приведен пример использования notify.

Листинг 20.4. Уведомление в системе Rinda

require 'rinda/tuplespace'

ts = Rinda::TupleSpace.new

alberts = ts.notify 'write', ['Albert', nil]

martins = ts.notify 'take', ['Martin', nil]

thr1 = Thread.new do

 alberts.each {|op,t| puts '#{op}: #{t.join(' ')}' }

end

thr2 = Thread.new do

 martins.each {|op,t| puts '#{op}: #{t.join(' ')}' }

end

sleep 1

ts.write ['Martin', 'Luther']

ts.write ['Albert', 'Einstein']

ts.write ['Martin', 'Fowler']

ts.write ['Alberf, 'Schweitzer']

ts.write ['Martin', 'Scorsese']

ts.take ['Martin', 'Luther']

# Выводится:

# write: Albert Einstein

# write: Albert Schweitzer

# take: Martin Luther

Мы видели, что read и другие операции пользуются шаблонами для сопоставления с образцами (и этим напоминают регулярные выражения). Мы уже знаем, что nil выступает в роли метасимвола, но можно указать и класс; ему будет соответствовать любой экземпляр этого класса.

tem1 = ['X', Integer]  # Соответствует ['X',5], но не ['X','Files'].

tem2 = ['X', NilClass] # Соответствует литералу nil в кортеже.

Кроме того, разрешается определять собственный оператор ветвящегося равенства (===), если вы хотите проводить сопоставление особым способом. В противном случае для сравнения будет использован стандартный оператор ===.

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

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату