Доступ к переменным потока потоков, хранящихся в переменных экземпляра - PullRequest
3 голосов
/ 21 июня 2019

Это ожидается,

t = Thread.new{
 Thread.current[:rabbit] = 'white'
}

#####  t[:rabbit] = white

Но я не могу понять это:

class Whatever
 def initialize
  @thd = Thread.new{
   Thread.current[:apple] = 'whatever'
  }
 end

 def apple
  @thd[:apple] 
 end

 def thd
  @thd
 end
end

Я хочу получить к ним доступ, почему они nil?

Whatever.new.apple # nil

Whatever.new.thd[:apple] # nil

Whatever.new.thd.thread_variable_get(:apple) # nil

Почему это происходит?Как я могу получить доступ к @thd переменным потока?

1 Ответ

4 голосов
/ 21 июня 2019

То, что вы видите здесь, это состояние гонки.Вы пытаетесь прочитать переменную потока до того, как тело потока будет выполнено .

Сравните следующее:

w = Whatever.new
w.apple
# => nil

w = Whatever.new
sleep 0.1
w.apple
# => "whatever"

Независимо от того, запускается ли тело потока во времени с Whatever.new.apple, это довольно случайно, кажется, это происходит в 0,1% времени для меня,но это, вероятно, отличается на других машинах

1000.times.
  map { Whatever.new.apple }.
  each_with_object(Hash.new(0)) { |val, memo| memo[val] += 1 }
# => {nil=>999, "whatever"=>1}

2000.times.
  map { Whatever.new.apple }.
  each_with_object(Hash.new(0)) { |val, memo| memo[val] += 1 }
# => {nil=>1998, "whatever"=>2}

(примечание: я не могу попробовать с большим числом итераций, потому что большое количество порождения потока приводит к исчерпанию ресурсов моего IRB)

Это относится к тому, что я слышал, описал как «правило асинхронности номер один», а именно, что вы не можете получить возвращаемое значение асинхронного метода из синхронного.Обычный способ справиться с этим - с помощью «обратного вызова», который Ruby может делать в виде yield / blocks.

Я рекомендую поискать учебник о том, как выполнять асинхронное программирование в Ruby.

...