如何使用Rails进行线程安全单例,如何保持我的类变量安全?

Mat*_*rix 3 singleton static-variables thread-safety class-variables ruby-on-rails-4

我已经读过Is Rails无共享或者可以单独请求访问相同的运行时变量吗?他们解释我的问题:

类变量可能在我的rails srver的两个请求之间共享,但解决方案在哪里!?

如何在请求之间实现安全单例?

class Foo
  @@instances = []
end
Run Code Online (Sandbox Code Playgroud)

我怎样才能确定每个请求HTTP都会重置实例?!

编辑:

我发现"config.reload_classes_only_on_change = false"解决方案,但我不确定它是最好的性能.
这个选项有什么后果?

我有一个例子来测试安全类变量:

class Test
   def self.log
      @test ||= false
      puts @test
      @test = true
   end
end


class ApplicationController < ActionController::Base
   def index
      Test.log
      Test.log
   end
end
Run Code Online (Sandbox Code Playgroud)

如果我通过重新加载动作(F5)启动此代码,我希望每次在rails服务器的日志中读取"false".但是,默认情况下它只是第一次"假".

编辑2:实际上这个选项重装类,但没有解决线程中的concurency问题.类变量被重置,但它们可以被其他线程修改.

线程安全类变量如何?

And*_*ing 5

我使用request_store gem,它很棒.

我的用例是将方法添加到用户模型类,如current_user,它们的语言环境,位置等,因为我的其他模型通常需要此信息.

我只是从我的应用程序控制器设置当前用户:

User.current = the_authenticated_user
User.request = request
Run Code Online (Sandbox Code Playgroud)

在我的用户模型类中:

class User
  def self.current
    RequestStore.store[:current_user]
  end

  def self.current=(user)
    RequestStore.store[:current_user] = user
  end

  def self.request
    RequestStore.store[:current_request]
  end

  def self.request=(request)
    # stash the request so things like IP address and GEO-IP based location is available to other models
    RequestStore.store[:current_request] = request
  end

  def self.location
    # resolve the location just once per request
    RequestStore.store[:current_location] ||= self.request.try(:location)
  end
end
Run Code Online (Sandbox Code Playgroud)

我没有启用重载类选项,因为它会导致太多问题,我已经目睹了多个版本的类.如果使用模型继承(即STI),延迟加载和/或动态类加载通常会破坏模型类的解析方式.您需要在基础和中间模型类中使用require_dependency以确保下载类也被加载.

我的开发设置镜像我的生产设置wrt类处理这是不方便的(需要在更改后重新启动服务器)但比追逐不存在的错误更方便.该重播宝石可以监视文件系统的变化,并重新启动服务器,你,让你在发展得到可靠的变化处理,虽然慢于轨道碎类重载.

配置/环境/ development.rb:

# Rails class reloading is broken, anytime a class references another you get multiple
# class instances for the same named class and that breaks everything. This is especially
# important in Sequel as models resolve classes once.
# So always cache classes (true)
config.cache_classes = true

# Always eager load so that all model classes are known and STI works
config.eager_load = true
Run Code Online (Sandbox Code Playgroud)

问:线程安全类变量如何?

答:除非受到保护,否则没有变量是线程安全的synchronize.

从体系结构的角度来看,Rails中的线程是浪费时间.我能够获得真正的并行性能/并发性的唯一方法是多个进程.它还避免了锁定和线程相关的开销,这些开销在长时间运行的进程中是不存在的.我使用Ruby 2.x的线程测试了并行CPU密集型代码,并没有完全没有并行性.每个核心使用1个ruby进程,我得到了真正的并行性.

我会认真考虑使用多个进程进行精简,然后决定是否要使用Thin + EventMachine来提高每个进程的总吞吐量.