Программирование на языке Ruby - [228]
Пока реализация пространства кортежей кажется ничем не примечательной. Но все становится гораздо интереснее, стоит лишь осознать, что к нему могут обращаться многие клиенты и доступ должен синхронизироваться. Короче говоря, это распределенная сущность; любой клиент может читать из пространства кортежей или писать в него, то есть его можно рассматривать как большое распределенное хранилище или даже способ коммуникации.
Первой реализацией пространства кортежей был проект Linda — исследование в области параллельного программирования, выполненное в Йельском университете в 1980-х годах. Реализация на языке Ruby (конечно, на основе библиотеки >drb
), естественно, называется Rinda.
Кортеж в Rinda может быть массивом или хэшем. На хэш налагается дополнительное ограничение: все ключи должны быть строками. Вот несколько примеров простых кортежей:
>t1 = [:add, 5, 9]
>t2 = [:name, :add_service, Adder.new, nil]
>t3 = { 'type' => 'add', 'value_1' => 5, 'value_2' => 9 }
Элемент кортежа может быть произвольным объектом; это работает, потому что >drb
умеет выполнять маршалинг и демаршалинг объектов Ruby. (Конечно, необходимо либо включить модуль >DRbUndumped
, либо сделать определения объектов доступными серверу.)
Пространство объектов создается методом >new
:
>require 'rinda/tuplespace'
>ts = Rinda::TupleSpace.new
># ...
Поэтому сервер выглядит так:
>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.
>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
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
Сейчас во многих школах, институтах и других учебных заведениях можно встретить компьютеры старого парка, уже отслужившие свое как морально, так и физически. На таких компьютерах можно изучать разве что Dos, что далеко от реалий сегодняшнего дня. К тому же у большинства, как правило, жесткий диск уже в нерабочем состоянии. Но и выбросить жалко, а новых никто не дает. Различные спонсоры, меценаты, бывает, подарят компьютер (один) и радуются, как дети. Спасибо, конечно, большое, но проблемы, как вы понимаете, этот компьютер в общем не решает, даже наоборот, усугубляет, работать на старых уже как-то не хочется, теперь просто есть с чем сравнивать.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.