2013-04-21 16 views
2

我想能够调用一个方法,在一个单独的线程上重复x次的时间,每隔几个时间发送消息如“仍在运行”到控制台,而我可以自由地调用其他方法来做同样的事情。你如何在Ruby中的线程发送字符串回到父线程

这在我的测试环境中工作,一切都通过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的和我能看到打印到控制台的字符串):

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

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

总之,我不理解如何让线程相互适当地沟通 - 或者如何将它们彼此同步(我不认为thread.join在这里是合适的,因为它会离开主线程如果我选择在将来一次发送一个,则无法接受另一个方法调用)。 我对Ruby多线程的理解很弱,任何人都能理解我想要在这里得到什么,并将我推向正确的方向?

+0

我已经把这个移动到堆栈溢出,因为Code Review不是问“我该怎么”问题的正确位置。 – sepp2k 2013-04-21 09:54:54

回答

0

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

require 'pp' 

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

$stdout.sync = $stderr.sync = true 

到您的二进制/可执行脚本,这样你的输出不是由IO类的内部缓冲,而是直接传递给操作系统。