#ruby #ruby-on-rails-6
#ruby #ruby-on-rails-6
Вопрос:
Безопасен ли поток следующего кода? Я беспокоюсь, что srand может быть переменной, которая не является потокобезопасной. У меня есть приложение rails, и я собираюсь использовать Puma с 5-10 потоками. Я не хочу вызывать проблемы.
class Test
def initialize(seed)
srand seed # => 1, 222, 222, 111
end # => :initialize
def letter
%w[a b c d e f g h i j k l m n o p q r s t u v w x y z aa bb cc dd].sample # => "g", "u"
end # => :letter
def letter1
%w[a b c d e f g h i j k l m n o p q r s t u v w x y z aa bb cc dd].sample # => "g", "u"
end # => :letter1
end # => :letter1
Test.new(222).letter # => "g"
Test.new(222).letter1 # => "g"
Test.new(111).letter # => "u"
Test.new(111).letter1 # => "u"
Ответ №1:
Зависит от того, что вы подразумеваете под «потокобезопасным». Программа все равно будет работать, Ruby не перейдет в несогласованное состояние, и никакие данные не будут потеряны. Однако генератор случайных чисел по умолчанию является глобальным, разделяемым между потоками; это будет зависеть от времени потока, чтобы увидеть, какой поток получает какое случайное число. Если вы хотите, чтобы все потоки просто получали случайные числа из одного RNG, ваш код в порядке, хотя результаты могут быть не повторяемыми, что, вероятно, противоречит цели srand
.
Если вы хотите убедиться, что каждый Test
из них генерирует числа только независимо (и повторяемо), вы хотите, чтобы у каждого Test
был свой собственный генератор случайных чисел:
class Test
def initialize(seed)
@random = Random.new(seed)
end
def letter
%w[a b c d e f g h i j k l m n o p q r s t u v w x y z aa bb cc dd].sample(random: @random)
end
end
t1 = Test.new(111)
t2 = Test.new(222)
3.times.map { t1.letter }
# => ["u", "m", "u"]
3.times.map { t2.letter }
# => ["u", "m", "u"]