Является ли Regexp.last_match потоком безопасно? - PullRequest
16 голосов
/ 25 января 2012

Это код, на который я смотрю:

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?

Ответы [ 3 ]

24 голосов
/ 25 января 2012

В документации по платформе Ruby 1.9.2 говорится, что вызов Regexp.last_match эквивалентен чтению специальной глобальной переменной $~.

Из "Языка программирования Ruby", стр. 318: "важно помнить, что $ ~ и все переменные, полученные из него, являются локальными для потоков и локальными для методов."

То есть Regexp.last_match является поточно-ориентированным. Что касается других методов, которые вы используете в method_missing, я считаю, что они также поточно-ориентированы. (Если кто-то знает иначе, пожалуйста, отредактируйте этот пост.)

6 голосов
/ 17 февраля 2016

TL; DR

Да, Специальные глобальные переменные Regexp являются поточно-ориентированными, потому что они не являются глобальными. Несмотря на то, что переменные в названии имеют слово «global», в документации написано:

Эти глобальные переменные являются локальными переменными потока и локальными методами.

Тема

Вы можете доказать это себе в отклике irb или pry. Например, чтобы проверить область видимости переменных внутри потоков:

# 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 выглядят как настоящие глобалы из-за префикса $, но не сохраняются вне окружающего потока или метода. В какой степени это оправдывает называть их «глобальными» вообще - это то, с чем вам придется столкнуться с разработчиками языка или сообщить об ошибке, если вы твердо убеждены, что это вводит в заблуждение.

0 голосов
/ 30 апреля 2019

Казалось бы, это говорит о том, что использование потока в ответе @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:0x00007f8cfc971090@(irb):2 run>
irb(main):006:0> thread_match
=> "In thread: \"F\""
irb(main):007:0>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...