2013-04-21 38 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類的內部緩衝,而是直接傳遞給操作系統。