Rails中的类实例变量应该在互斥锁中设置吗?

Mat*_*ins 5 ruby synchronization ruby-on-rails ruby-on-rails-3

假设我的Rails项目中有一个设置实例变量的Ruby类.

class Something
  def self.objects
    @objects ||= begin
      # some logic that builds an array, which is ultimately stored in @objects
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

有可能@objects可以设置多次吗?是否有可能在一个请求期间,在begin/ end上面执行代码时,可以在第二个请求期间调用此方法?我想这实际上归结为Rails服务器实例如何分叉的问题.

我应该使用Mutex或线程同步吗?例如:

class Something
  def self.objects
    return @objects if @objects

    Thread.exclusive do
      @objects ||= begin
        # some logic that builds an array, which is ultimately stored in @objects
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

Yeh*_*atz 7

即使在MRI中,也可以(并且可取)以多线程模式运行Rails.这可以通过更改一行来完成production.rb.

config.threadsafe!
Run Code Online (Sandbox Code Playgroud)

在MRI中,两个线程不能同时运行代码,但是上下文切换可以随时发生.在Rubinius和JRuby中,线程可以同时运行代码.

让我们看看你展示的代码:

class Something
  def self.objects
    @objects ||= begin
      # some logic that builds an array, which is ultimately stored in @objects
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

||=代码被扩展为类似:

class Something
  def self.objects
    @objects || (@objects = begin
      # some logic that builds an array, which is ultimately stored in @objects
    end)
  end
end
Run Code Online (Sandbox Code Playgroud)

这意味着该过程实际上有两个步骤:

  1. 抬头 @objects
  2. 如果@objects是假的,则设置@objectsbegin/end表达式的结果

上下文可以在这些步骤之间切换.上下文当然可以在步骤2的中间切换.这意味着您可能会多次运行块而不是一次.在MRI中,这可能是可以接受的,但是在表达式周围锁定互斥体是完全直截了当的,所以这样做.

class Something
  MUTEX = Mutex.new

  def self.objects
    MUTEX.synchronize do
      @objects ||= begin
        # some logic that builds an array, which is ultimately stored in @objects
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)


Pat*_*ann 6

我会捅一下.

Rails是单线程的.对Rails应用程序的连续请求要么排队,要么由单独的应用程序实例处理(读取:进程).类中@objects定义的类实例变量的值Something存在于进程的范围内,而不在应用程序的任何实例的范围内.

因此,互斥体是不必要的,因为您永远不会遇到两个进程正在访问同一资源的情况,因为这两个进程的内存空间完全是分开的.

我认为这提出了另一个问题,@objects意图是共享资源,如果是这样,我认为它需要以不同的方式实现.

免责声明:我可能在这里完全不合适,事实上我有点希望我今天能学到一些东西:)