Regexp.last_match线程安全吗?

时间:2012-01-25 14:24:10

标签: ruby

这是我正在查看的代码:

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 个答案:

答案 0 :(得分:24)

Ruby 1.9.2平台文档声明调用Regexp.last_match等同于读取特殊的$~全局变量。

从“Ruby编程语言”,第318页:“重要的是要记住$〜和从它派生的变量都是线程本地的和方法本地的。”

所以Regexp.last_match 是线程安全的。至于您在method_missing中使用的其他方法,我相信它们也是线程安全的。 (如果有人不同,请编辑这篇文章。)

答案 1 :(得分:6)

TL; DR

是的,Regexp special global variables是线程安全的,因为它们不是真正的全局变量。尽管变量在名称中包含“global”一词,但文档说:

  

这些全局变量是线程局部变量和方法局部变量。

线程

你可以用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特殊变量看起来像一样真正的全局变量,但是不要在封闭线程或方法之外保留。在多大程度上证明称他们为“全局”是你必须要接受语言设计师的事情,或者提出一个错误,如果你强烈认为这是误导性的。

答案 2 :(得分:0)

这似乎表明使用@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>