Почему метод put ведет себя странно при использовании в потоке? - PullRequest
1 голос
/ 02 февраля 2012

РЕШЕНИЕ: В файле .irbc, положить: IRB.conf[:USE_READLINE] = false

Я использую какой-нибудь рубиновый код:

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

Когда я запускаю это в irb и появляется всплывающая очередь, она печатает «1», но сразу не печатает «2». Я должен нажать Enter пару раз, прежде чем он выплевывает "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?> 

Ответы [ 2 ]

2 голосов
/ 07 февраля 2012

Я немного поэкспериментировал и выяснил, что происходит.Как вы, возможно, знаете, два потока 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. </p>

В вашем примере, каждый раз, когда вы нажимаете enter, поток получает долю секунды для выполнения - достаточно времени, чтобы записать число илиновая строка.Затем ruby ​​переключается обратно на поток irb, который записывает приглашение и ожидает ввода.

* В JRuby, IronRuby и Rubinius 2.0 несколько потоков могут работать одновременно.

Edit: Я тестировал на Windows, и там продолжают работать потоки.Если вы хотите, чтобы потоки продолжали работать на Mac, вы можете сохранить это как, скажем, sirb.rb (простой irb) и использовать его вместо irb:

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

Обратите внимание, что, в отличие от irb, он не 't не поддерживает оператор, занимающий несколько строк, и не поддерживает перемещение каретки для редактирования или нажатие кнопки «Вверх» для истории (в Mac OS X).Пример:

> for i in 1..10; print i ** 2, " "; end; puts
1 4 9 16 25 36 49 64 81 100 
nil
0 голосов
/ 02 февраля 2012

Я не понимаю, что вы получаете. Эти два числа печатаются в одну миллисекунду на моей машине. (Я пробовал это под 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, я не могу понять, связано ли это с Ruby в OS X Lion, но это было бы моим подозрением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...