2

我希望能够调用一个在单独的线程上重复 x 次的方法,该线程每隔几分钟就会向控制台发送诸如“仍在运行”之类的消息,而我可以自由地调用其他执行相同操作的方法。

这在我的测试环境中有效,并且所有内容都通过 rspec 检查 - 但是当我将代码移动到 gem 并从另一个脚本调用它时,代码似乎在其他线程中工作,但字符串永远不会发送到我的控制台(或我能告诉的任何地方)。

我将把代码的重要部分放在下面,但为了更好地理解,重要的是要知道:

  1. 该代码将按设定的时间间隔检查股票市场价格,以便在所述股票的价值达到特定价格时通知用户。
  2. 代码应向控制台打印一条消息,说明当价格未达到时代码仍在运行。
  3. 代码应该告诉用户股票已经达到目标价格,然后停止循环。

这是代码:

require "trade_watcher/version"
require "market_beat"

module TradeWatcher


  def self.check_stock_every_x_seconds_for_value(symbol, seconds, value)
    t1 = Thread.new{(self.checker(symbol, seconds, value))} 
  end

  private
      def self.checker(symbol, seconds, value)
        stop_time = get_stop_time
        pp stop_time
        until is_stock_at_or_above_value(symbol, value) || Time.now >= stop_time
          pp "#{Time.now} #{symbol} has not yet met your target of #{value}."
          sleep(seconds)
        end
        if Time.now >= stop_time
          out_of_time(symbol, value)
        else
          reached_target(symbol, value)
        end
      end

      def self.get_stop_time
        Time.now + 3600 # an hour from Time.now
      end

      def self.reached_target(symbol, value)
        pp "#{Time.now} #{symbol} has met or exceeded your target of #{value}."
      end

      def self.out_of_time(symbol, value)
        pp "#{Time.now} The monitoring of #{symbol} with a target of #{value} has expired due to the time limit of 1 hour being rached."
      end

      def self.last_trade(symbol)
        MarketBeat.last_trade_real_time symbol
      end

      def self.is_stock_at_or_above_value(symbol, value)
        last_trade(symbol).to_f >= value
      end
end

以下是测试(全部通过):

require 'spec_helper'

describe  "TradeWatcher" do
  context "when comparing quotes to targets values" do
    it "can report true if a quote is above a target value" do
      TradeWatcher.stub!(:last_trade).and_return(901)
      TradeWatcher.is_stock_at_or_above_value(:AAPL, 900).should == true
    end

    it "can report false if a quote is below a target value" do
      TradeWatcher.stub!(:last_trade).and_return(901)
      TradeWatcher.is_stock_at_or_above_value(:AAPL, 1000).should == false
    end
  end

  it "checks stock value multiple times while stock is not at or above the target value" do
    TradeWatcher.stub!(:last_trade).and_return(200)
    TradeWatcher.should_receive(:is_stock_at_or_above_value).at_least(2).times
    TradeWatcher.check_stock_every_x_seconds_for_value(:AAPL, 1, 400.01)
    sleep(2)
  end

  it "triggers target_value_reahed when the stock has met or surpassed the target value" do
    TradeWatcher.stub!(:last_trade).and_return(200)
    TradeWatcher.should_receive(:reached_target).exactly(1).times
    TradeWatcher.check_stock_every_x_seconds_for_value(:AAPL, 1, 100.01)
    sleep(2)
  end

  it "returns a 'time limit reached' message once a stock has been monitored for the maximum of 1 hour" do
    TradeWatcher.stub!(:last_trade).and_return(200)
    TradeWatcher.stub!(:get_stop_time).and_return(Time.now - 3700)
    TradeWatcher.check_stock_every_x_seconds_for_value(:AAPL, 1, 100.01)
    TradeWatcher.should_receive(:out_of_time).exactly(1).times
    sleep(2)
  end

end

这是一个非常简单的脚本(在我的理解中)应该打印“{Time.now} AAPL 尚未达到您的 800.54 目标。” 每隔 1 秒,该方法仍在运行,并且至少应该可见 20 秒(我在 rspec 中使用 sleep 对此进行了测试,并且能够看到打印到控制台的字符串):

require 'trade_watcher'
TradeWatcher.check_stock_every_x_seconds_for_value(:AAPL, 1, 800.54)
sleep (20)

但是我没有得到任何输出 - 尽管程序确实等待 20 秒才能完成。如果我添加其他行以打印到控制台,它们工作得很好,但我的 TradeWatcher 方法调用触发的线程中没有任何实际工作。

简而言之,我不明白如何让线程相互适当地进行通信 - 或者如何将它们相互同步(我认为 thread.join 在这里不合适,因为它会使主线程挂起并且无法如果我以后选择一次发送一个方法调用,请接受另一个方法调用)。 我对 Ruby 多线程的理解很薄弱,任何人都能够理解我在这里想要达到的目的并推动我朝着正确的方向前进?

4

1 回答 1

0

当你去打印时,看起来 pp 函数根本还没有被 ruby​​ 加载。通过添加:

require 'pp'

到 trade_watcher.rb 的顶部,我能够得到你期望的输出。您可能还需要考虑添加:

$stdout.sync = $stderr.sync = true

到你的二进制/可执行脚本,这样你的输出就不会被 IO 类在内部缓冲,而是直接传递给 os.

于 2014-03-22T18:05:18.887 回答