【问题标题】:Why does the puts method behave strangely when used in a thread?为什么在线程中使用 puts 方法时会出现奇怪的行为?
【发布时间】:2012-02-01 23:39:16
【问题描述】:

解决方案:在 .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”之前,我必须按几次 Enter。这是为什么呢?

这是我的 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 版本是否在编译时启用了线程支持?
  • @andrewdotnich:你为什么要删除 OS X lion 标签?
  • @AndrewGrimm:因为我可以在雪豹上复制它。这可能是 *nix 实现的问题,但不是仅限于 Lion……

标签: ruby multithreading


【解决方案1】:

我做了一些实验,发现发生了什么。您可能知道,两个 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 使用了

在您的示例中,每次您按下回车键时,线程都会在瞬间执行——足够的时间来写出一个数字或换行符。然后 ruby​​ 切换回 irb 的线程,写入提示并等待输入。

* 使用 JRuby、IronRuby 和 Rubinius 2.0,可以同时运行多个线程。

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

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

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

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

【讨论】:

  • 谢谢。您能否建议我如何在仍然能够输入 ruby​​ 代码(如 irb)的同时监视线程的替代方案?基本上,我正在尝试记录每个单独线程的信息,以便查看程序在多个线程下工作时的行为方式
  • @PragmaOnce:我编辑了答案以添加 irb 的替代方案。希望对您有所帮助。
  • 谢谢你!当您在 Windows 上测试它时,您是否也在使用 IRB 或其他一些 ruby​​ shell?你认为这个问题是 Mac 特有的吗?某些 linux 变体会像 windows 一样工作吗?
  • 找到了修复它的方法。在 .irbc 文件中,包含 "IRB.conf[:USE_READLINE] = false"
【解决方案2】:

我没有得到你得到的东西。这两个数字在我的机器上以相同的毫秒打印。 (我在 Windows 机器上试了下 1.8.7,还是得到了这个结果)

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 Lion 上的 Ruby 有关,但我对此表示怀疑。

【讨论】:

  • 是的。检查我原来的问题。我更新了我得到的东西
  • 嗯...不会发生在我身上。这就是为什么我问什么可能是错的。请检查我原来的问题,看看我得到了什么。
  • @PragmaOnce:好的,你的操作系统和 ruby​​ 版本是什么?你能做irb --versionruby --version,然后进入irb做puts RUBY_VERSION吗?
  • @PragmaOnce:抱歉,我无权访问该操作系统。我不能再帮你了。
  • 谢谢。欣赏它!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-27
  • 1970-01-01
  • 2020-02-05
  • 2021-08-26
相关资源
最近更新 更多