Является ли Regexp.last_match потоком безопасным?
Это код, на который я смотрю:
def method_missing(id, *args)
return self.find(Regexp.last_match(1), args[0]) if id.id2name =~ /find_by_(.+)/
raise NoMethodError
end
Что произойдет, если у меня есть несколько потоков, вызывающих Regexp.last_match
?
Что произойдет, если у меня есть несколько потоков, вызывающих объект с помощью метода method_missing
?
Ответы
Ответ 1
В документах платформы Ruby 1.9.2 указано, что вызов Regexp.last_match
эквивалентен чтению специальной переменной $~
.
Из "Язык программирования Ruby", стр. 318: "важно помнить, что $~ и полученные из него переменные являются локальными и локальными методами."
So Regexp.last_match
является потокобезопасным. Что касается других методов, которые вы используете в method_missing
, я считаю, что они также потокобезопасны. (Если кто-то знает по-другому, отредактируйте этот пост.)
Ответ 2
TL; DR
Да, специальные глобальные переменные Regexp являются поточно- ориентированными, потому что они не являются глобальными. Несмотря на то, что переменные имеют в названии слово "глобальный", в документации говорится:
Эти глобальные переменные являются локальными переменными потока и переменными метода.
Потоки
Вы можете доказать это себе в irb или pry REPL. Например, чтобы проверить область действия переменных внутри потоков:
# Ensure $~ and friends are nil in case this isn't a fresh REPL.
''.match /foo/
# Make this variable available inside the thread block.
thread_match = nil
Thread.new do
'foo'.match /(foo)/
thread_match = "In thread: #{$1.inspect}"
end
[thread_match, "Global value: #{$1.inspect}"]
#=> ["In thread: \"foo\"", "Global value: nil"]
методы
Эти специальные переменные даже не являются действительно глобальными при использовании внутри метода. Учтите следующее:
def foo
'foo'.match /(foo)/
p $1
end
[foo, $1]
#=> ["foo", nil]
Заключение
Другими словами, специальные переменные Regexp выглядят как настоящие глобальные переменные из- $
префикса $
, но не сохраняются вне окружающего потока или метода. В какой степени это оправдывает называть их "глобальными" вообще - это то, с чем вам придется столкнуться с разработчиками языка или сообщить об ошибке, если вы твердо уверены, что она вводит в заблуждение.
Ответ 3
Казалось бы, это говорит о том, что использование потока в ответе @Todd A. Jacobs не является поточно-ориентированным.
➜ ~ irb
irb(main):001:0> thread_match = nil
=> nil
irb(main):002:0> Thread.new do
irb(main):003:1* /([[:alpha:]])*/.match('BF92')
irb(main):004:1> thread_match = "In thread: #{$1.inspect}"
irb(main):005:1> end
=> #<Thread:[email protected](irb):2 run>
irb(main):006:0> thread_match
=> "In thread: \"F\""
irb(main):007:0>