你如何让Ruby中的线程将字符串发送回父线程

时间:2013-04-21 05:58:38

标签: ruby multithreading

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

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

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

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

    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多线程的理解很弱,任何人都能够理解我想要在这里得到什么并向我推进正确的方向?

1 个答案:

答案 0 :(得分:0)

当你去打印时,看起来像是没有用ruby加载pp函数。添加:

require 'pp'

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

$stdout.sync = $stderr.sync = true

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