Лучший способ запрограммировать "Ruby-подобную" сеть влияния в Ruby?
У меня есть сеть узлов, каждый из которых влияет на состояние некоторых других узлов (представьте электронную таблицу Excel со значениями ячеек, зависящими от других ячеек с помощью формул).
Мне интересно, какой самый чистый способ реализовать это в Ruby?
Конечно, у меня может быть один процесс на узел, но как он будет работать, если число узлов увеличится? И я уверен, что есть библиотеки для этого, но я не могу найти современную.
Спасибо за вашу помощь!
Обновление: Похоже, что EventMachine может сделать эту работу... но он кажется более приспособленным к небольшому количеству "узлов"
3 ответа
Это звучит как хорошая ситуация для наблюдателя. Вот пример этого в ruby:
require 'observer'
class Node
attr_accessor :id
@@current_node_id = 0
def initialize
@@current_node_id += 1
id = @@current_node_id
end
include Observable
attr_reader :value
protected
def value=(new_value)
return if @value == new_value
old_value = @value
@value = new_value
changed
notify_observers(id, old_value, @value)
end
end
class ValueNode < Node
def initialize(initial_value)
super()
@value = initial_value
end
def value=(new_value)
super(new_value)
end
end
class SumNode < Node
def initialize(*nodes)
super()
@value = nodes.map(&:value).inject(0, &:+)
nodes.each do |node|
node.add_observer(self)
end
end
def update(id, old_value, new_value)
self.value = self.value - old_value + new_value
end
end
def test
v1 = ValueNode.new 4
v2 = ValueNode.new 8
sum = SumNode.new(v1, v2)
sum2 = SumNode.new(v1, sum)
v2.value = 10
p sum.value
p sum2.value
end
test()
Обратите внимание, как значение SumNode
не пересчитывается при каждом запросе - вместо этого он обновляется при обновлении одного из его узлов значений. Это работает рекурсивно, так что внутренний SumNodes
также запускать обновления. Поскольку уведомление включает в себя уникальный id
узла, можно написать более сложный Node
типы, такие как те, которые содержат формулы.
См. http://www.ruby-doc.org/stdlib/libdoc/observer/rdoc/index.html для получения дополнительной информации о Observable.
Это похоже на часто используемую парадигму Twitter, где обновления одного пользователя рассылаются всем его последователям. Чтобы сделать это эффективно, вы должны хранить два списка для данного человека: один с людьми, за которыми он следует, а другой с людьми, которые следуют за ним. Вы можете сделать то же самое для списка узлов. Когда узел изменяется, вы можете быстро найти узлы, на которые влияет этот узел. Когда связь исчезнет, вам понадобится "прямой" список, чтобы узнать, из каких списков "удалить" обратную связь.
Вы можете хранить эти списки в двухмерных массивах или в чем-то вроде Redis. Я не очень понимаю, как вписывается EventMachine.
Если у вас есть сетевой график зависимостей и вы хотите, чтобы они масштабировались, лучше всего будет использовать базу данных графиков. Neo4J - это популярная и мощная база данных для отслеживания зависимостей этого типа.
Существует несколько способов взаимодействия с Neo4J из Ruby:
- Вы можете использовать JRuby и его интерфейс Java.
- Используйте его REST API
- Используйте neo4j.rb или одну из других библиотек интерфейса Ruby.