Ruby on rails Rails中的类实例变量应该在互斥对象中设置吗?

Ruby on rails Rails中的类实例变量应该在互斥对象中设置吗?,ruby-on-rails,ruby,ruby-on-rails-3,synchronization,Ruby On Rails,Ruby,Ruby On Rails 3,Synchronization,假设我在Rails项目中有一个Ruby类,它正在设置一个实例变量 class Something def self.objects @objects ||= begin # some logic that builds an array, which is ultimately stored in @objects end end end 是否可以多次设置@objects?在一个请求期间,当执行上述开始/结束之间的代码时,是否可能在第二个请求期间调用此方法?

假设我在Rails项目中有一个Ruby类,它正在设置一个实例变量

class Something
  def self.objects
    @objects ||= begin
      # some logic that builds an array, which is ultimately stored in @objects
    end
  end
end
是否可以多次设置
@objects
?在一个请求期间,当执行上述
开始
/
结束
之间的代码时,是否可能在第二个请求期间调用此方法?我想这实际上是一个Rails服务器实例如何分叉的问题

我应该使用
互斥锁
还是线程同步?e、 g:

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
我要试试看

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

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

我认为这引发了另一个问题,
@objects
是否打算成为共享资源,如果是这样的话,我认为它需要以不同的方式实现

免责声明:我可能在这里完全偏离了主题,事实上我有点希望这样我今天就能学到一些东西:)

即使在MRI中,以多线程模式运行Rails也是可能的(也是可取的)。这可以通过更改
production.rb
中的一行来实现

config.threadsafe!
在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
| |=
代码将扩展为如下内容:

class Something
  def self.objects
    @objects || (@objects = begin
      # some logic that builds an array, which is ultimately stored in @objects
    end)
  end
end
这意味着该过程实际上有两个步骤:

  • 查找
    @对象
  • 如果
    @objects
    为falsy,则将
    @objects
    设置为
    开始/结束表达式的结果
  • 上下文可以在这些步骤之间切换。当然,上下文可以在步骤2的中间切换。这意味着您可能会多次运行块,而不是一次。在核磁共振成像中,这可能是可以接受的,但在表达式周围锁定互斥体是完全直接的,所以就这么做吧

    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
    

    我要请叶胡达称体重……我也不确定,但我相当肯定你是对的。:)我真的觉得你离现场很近。我对你的回答有一个警告,那就是使用的是哪个口译员。例如,JRuby可能存在这些问题。因为它确实有真正的线程支持,所以每个进程不仅仅是父进程的分支。所以对于MRI,我想你说得对。我应该提到我的问题主要集中在MRI上。我的印象基本上与你在回答中概述的相同,但我认为这是值得核实的
    @objects
    不打算成为共享资源,而只是一个缓存,以防止重复查找耗时的进程。谢谢执行
    def self.objects是否更有效@objects | | MUTEX.synchronize{@objects | |=[…]};结束
    -这样,如果已经设置了var,它就不会尝试获取锁了?另外,我们可以使用一个通用的
    线程.synchronize
    块吗?