Ruby publish/subscribe implementation issue

时间:2018-04-20 00:43:11

标签: ruby multithreading observable

I'm experimenting with Observable Ruby class that should be capable to provide Publish/Subscribe pattern.

I wrote this code to test the behavior:

require "observer"

class Ticker          ### Periodically fetch a stock price.
  include Observable
  attr_accessor :sleep_time

  def initialize(symbol, sleep_time)
    @symbol = symbol
    @sleep_time = sleep_time
  end

  def run
    last_price = nil
    loop do
      price = Price.fetch(@symbol)
      print "#{@symbol}, Current price: #{price}\n"
      if price != last_price
        changed                 # notify observers
        last_price = price
        notify_observers(price)
      end
      sleep @sleep_time
    end
  end
end

class Price           ### A mock class to fetch a stock price (60 - 140).
  def self.fetch(symbol)
    60 + rand(80)
  end
end

class Notification
  attr_accessor :name, :sleep_time
  def initialize(ticker, name, sleep_time)
    @name = name
    @sleep_time = sleep_time
    ticker.add_observer(self)
  end

  def update(price)
    puts @name + ': ' + price.to_s
    sleep @sleep_time
  end
end

ticker = Ticker.new("MSFT", 0.5)
t1 = Thread.new { slow_notification = Notification.new(ticker, 'thread 1', 0) }
t2 = Thread.new { fast_notification = Notification.new(ticker, 'thread 2', 5) }
ticker.run

I was expecting that fast_notification sent the notification faster than slow_notification cause the sleep time for the first is one is 0 seconds and for the other one 5 seconds. In practice, they run at the same time (every 5 seconds).

2 个答案:

答案 0 :(得分:1)

为了以异步方式处理它,线程创建应该在主循环内。我得到了这些变化的预期行为:

require "observer"

class Ticker          ### Periodically fetch a stock price.
  include Observable
  attr_accessor :sleep_time

  def initialize(symbol, sleep_time)
    @symbol = symbol
    @sleep_time = sleep_time
  end

  def run
    last_price = nil
    loop do
      price = Price.fetch(@symbol)
      #print "#{@symbol}, Current price: #{price}\n"
      if price != last_price
        changed                 # notify observers
        last_price = price
        Thread.new { notify_observers(price, Time.now) }
      end
      sleep @sleep_time
    end
  end
end

class Price           ### A mock class to fetch a stock price (60 - 140).
  def self.fetch(symbol)
    7600 + rand(800)
  end
end

class Notification
  attr_accessor :name, :sleep_time, :working, :mutex, :counter
  def initialize(ticker, name, sleep_time)
    @name = name
    @sleep_time = sleep_time
    @working = false
    @mutex = Mutex.new
    @counter = 0
    ticker.add_observer(self)
  end

  def do_something(price)
    puts @name + ': ' + price.to_s
    sleep @sleep_time
  end

  def update(price, time)
    @mutex.synchronize{
      do_something(price)
    }
  end
end

ticker = Ticker.new("MSFT", 0.5)
Notification.new(ticker, 'Fast notification', 0)
Notification.new(ticker, 'Slow notification', 5)
ticker.run

答案 1 :(得分:0)

我认为你应该刷新缓冲区。尝试在打印后添加STDOUT.flush

  def run
    last_price = nil
    loop do
      price = Price.fetch(@symbol)
      print "#{@symbol}, Current price: #{price}\n"
      STDOUT.flush
      if price != last_price
        changed                 # notify observers
        last_price = price
        notify_observers(price)
      end
      sleep @sleep_time
    end
  end