我已阅读Is Rails shared-nothing or can separate requests access the same runtime variables?并解释了我的问题:
类变量可能在我的rails srver的两个请求之间共享,但解决方案在哪里!?
如何在请求之间实现安全的单例?
class Foo
@@instances = []
end
如何确保为每个请求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
如果我通过重新加载动作(F5)启动此代码,我希望每次在rails服务器的日志中读取“false”。但是,默认情况下它只是第一次“假”。
编辑2: 实际上这个选项重装了类,但没有解决线程中的concurency问题。 类变量被重置,但它们可以被其他线程修改。
线程安全类变量如何?
答案 0 :(得分:5)
我使用request_store宝石,效果很好。
我的用例是将方法添加到用户模型类,例如current_user,它们的语言环境,位置等,因为我的其他模型通常需要这些信息。
我只是从我的应用程序控制器设置当前用户:
User.current = the_authenticated_user
User.request = request
在我的用户模型类中:
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
我没有启用重新加载类选项,因为它会导致太多问题,我已经目睹了多个版本的类。如果使用模型继承(即STI),延迟加载和/或动态类加载通常会破坏模型类的解析方式。您需要在基础和中间模型类中使用require_dependency以确保下载类也被加载。
我的开发设置镜像我的生产设置wrt类处理这不方便(需要在更改后重新启动服务器)但比追逐不存在的错误更方便。 rerun gem可以监视文件系统更改并为您重新启动服务器,以便在开发过程中获得可靠的更改处理,尽管比重新下载的类更糟糕。
<强>配置/环境/ 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
问:线程安全类变量如何?
答:除非受synchronize
保护,否则任何变量都不是线程安全的。
从架构角度来看,Rails中的线程是浪费时间。我能够获得真正的并行性能/并发性的唯一方法是多个进程。它还避免了锁定和线程相关的开销,这些开销在长时间运行的进程中并不存在。我使用Ruby 2.x的线程测试了并行CPU密集型代码,并没有完全没有并行性。每个核心使用1个ruby进程,我得到了真正的并行性。
我会认真考虑使用多个进程进行精简,然后决定是否要使用Thin + EventMachine来提高每个进程的总吞吐量。