在 Ruby 中对类变量执行写入/读取操作不是线程安全的。对实例变量执行写入/读取似乎是线程安全的。也就是说,对类或元类对象的实例变量执行写入/读取是否线程安全?
这三个(人为的)示例在线程安全方面有何区别?
示例 1:相互排斥
class BestUser # (singleton class)
@@instance_lock = Mutex.new
# Memoize instance
def self.instance
@@instance_lock.synchronize do
@@instance ||= best
end
end
end
示例 2:实例变量存储
class BestUser # (singleton class)
# Memoize instance
def self.instance
@instance ||= best
end
end
示例 3: METACLASS 上的实例变量存储
class BestUser # (singleton class)
# Memoize instance
class << self
def instance
@instance ||= best
end
end
end
最佳答案
例2和例3完全一样。模块和类也是对象,在一个对象上定义一个单例方法实际上是在它的单例类上定义它。
话虽如此,并且由于您已经确定实例变量访问是线程安全的,因此示例 2 和 3 也是线程安全的。例1应该也是线程安全的,但不如另外两个,因为它需要手动变量同步。
但是,如果您需要利用类变量在继承树中共享这一事实,您可能必须使用第一种方法。
Ruby 语言固有的线程安全性取决于实现。
MRI,在 1.9 之前,实现了线程 at the VM level .这意味着即使 Ruby 能够安排代码执行,但在单个 Ruby 进程中并没有真正并行运行。 Ruby 1.9 使用与 global interpreter lock 同步的 native 线程.只有持有锁的上下文才能执行代码。
n, x = 10, 0
n.times do
Thread.new do
n.times do
x += 1
end
end
end
sleep 1
puts x
# 100
x
的值在 MRI 上总是一致。然而,在 JRuby 上,情况发生了变化。同一算法的多次执行产生值 76
、87
、98
、88
、94
。结果可能是任何结果,因为 JRuby 使用 Java 线程,它们是真正的线程并并行执行。
就像在 Java 语言中一样,为了在 JRuby 中安全地使用线程,需要手动同步。以下代码始终为 x
生成一致的值:
require 'thread'
n, x, mutex = 10, 0, Mutex.new
n.times do
Thread.new do
n.times do
mutex.synchronize do
x += 1
end
end
end
end
sleep 1
puts x
# 100
关于ruby - 线程安全 : Class Variables in Ruby,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9558192/