为什么puts方法在线程中使用时表现得很奇怪



解决方案:在.irbc文件中,放入:IRB.conf[:USE_READLINE] = false

我正在运行一些ruby代码:

Thread.new do
 loop do
   a = @queue.pop
   puts "1"
   puts "2"
 end
end

当我在irb中运行这个程序,队列弹出时,它会打印"1",但不会立即打印"2"。在它吐出"2"之前,我必须按回车键几次。为什么?

这是我的irb日志:

>> Thread.new do
?>  loop do
?>    a = @queue.pop
>>    puts "1"
>>    puts "2"
>>  end
>> end
=> #<Thread:0x10ae6d1a0 sleep>
>> @queue << "something random"
1=> #<Queue:0x10aed6420>
>> 
?> 
?> 
?> 
2?> 

我得到的是:

>> require "thread"
=> true
>> 
?> @queue = Queue.new
=> #<Queue:0x101bc9a60>
>> 
?> Thread.new do
?>  loop do
?>    a = @queue.pop
>>    puts "1 was printed at #{Time.now.to_f}"
>>    puts "2 was printed at #{Time.now.to_f}"
>>  end
>> end
=> #<Thread:0x101bb8058 sleep>
>> 
?> @queue << 42
1 was printed at 1328144684.33667=> #<Queue:0x101bc9a60>
>> 
?> 
?> 
?> 
2 was printed at 1328144686.4642?> 

我做了一些实验,发现了正在发生的事情。正如您可能知道的,两个Ruby线程不能同时运行;它们只是快速地来回切换。*通常,如果您调用gets,调用线程将等待输入,其他线程将继续(因为gets释放了GIL)。然而,在irb中,(至少在Mac OS X上)其他线程在等待输入时不会继续执行。示例:

>> i = 0
=> 0
>> Thread.new { loop { i += 1 } }
=> #<Thread:0x1094d6d68 run>
>> i
=> 234866
>> i
=> 401271

如果线程正在执行,i将以百万计。(在irb外部测试。)此外,ruby使用<1%的CPU。

在您的示例中,每次按enter键时,线程都会有一瞬间的时间执行,这足够写一个数字或一条换行符。然后ruby切换回irb的线程,该线程编写提示并等待输入。

*使用JRuby、IronRuby和Rubinius2.0,可以同时运行多个线程。

编辑:我在Windows上进行了测试,线程一直在那里运行。如果你想让线程在Mac上继续运行,你可以把它保存为sirb.rb(简单的irb),并使用它来代替irb:

$stdout.sync = true
while true
    print "> "
    p(eval gets)
end

请注意,与irb不同,它不支持跨越多行的语句,也不支持移动插入符号进行编辑或按Up键查看历史记录(在Mac OS X上)。示例:

> for i in 1..10; print i ** 2, " "; end; puts
1 4 9 16 25 36 49 64 81 100 
nil

我没有得到你想要的。这两个数字在同一毫秒内打印在我的机器上。(我在1.8.7下在Windows机器上尝试过,但仍然得到了结果)

require "thread"
@queue = Queue.new
Thread.new do
 loop do
   a = @queue.pop
   puts "1 was printed at #{Time.now.to_f}"
   puts "2 was printed at #{Time.now.to_f}"
 end
end
@queue << 42
$ irb
irb(main):001:0> require "thread"
=> true
irb(main):002:0>
irb(main):003:0* @queue = Queue.new
=> #<Queue:0x1422d80 @que=[], @waiting=[], @mutex=#<Mutex:0x1422d20>>
irb(main):004:0>
irb(main):005:0* Thread.new do
irb(main):006:1*  loop do
irb(main):007:2*    a = @queue.pop
irb(main):008:2>    puts "1 was printed at #{Time.now.to_f}"
irb(main):009:2>    puts "2 was printed at #{Time.now.to_f}"
irb(main):010:2>  end
irb(main):011:1> end
=> #<Thread:0x14a4ec0 run>
irb(main):012:0>
irb(main):013:0* @queue << 42
1 was printed at 1328144503.01272
2 was printed at 1328144503.01272
=> #<Thread:0x14a4ec0 sleep>

由于我无法访问OS X Lion,我不知道这是否与OS X Lions上的Ruby有关,但这是我的怀疑。

最新更新