【发布时间】:2009-09-07 11:42:33
【问题描述】:
Rails 控制器是多线程的吗?
如果是这样,我是否可以通过简单的操作来保护某段代码(每十分钟触发一次)不被多个线程运行
require 'thread'
Thread.exclusive do
# stuff here
end
我需要以某种方式在监视器上同步吗?
【问题讨论】:
标签: ruby-on-rails ruby multithreading
Rails 控制器是多线程的吗?
如果是这样,我是否可以通过简单的操作来保护某段代码(每十分钟触发一次)不被多个线程运行
require 'thread'
Thread.exclusive do
# stuff here
end
我需要以某种方式在监视器上同步吗?
【问题讨论】:
标签: ruby-on-rails ruby multithreading
在基本的 Rails 应用程序上运行 rake middleware 会得到以下结果:
use Rack::Lock
use ActionController::Failsafe
use ActionController::Reloader
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
use ActiveRecord::SessionStore, #<Proc:0x017fb394@(eval):8>
use ActionController::RewindableInput
use ActionController::ParamsParser
use Rack::MethodOverride
use Rack::Head
run ActionController::Dispatcher.new
机架堆栈上的第一项是Rack::Lock。这会对每个请求进行锁定,因此一次只处理一个请求。因此,标准 rails 应用程序是单线程的。但是,您可以在使您的应用程序多线程的请求中生成新线程,大多数人从未遇到过这种情况。
如果您遇到问题……
require 'thread'
Thread.exclusive do
# stuff here
end
... 将确保块内的内容永远不会与 any 其他代码并行运行。在所有线程之间创建共享Mutext(在类变量或其他东西中,但是在开发模式下重新加载时可能会被擦除,所以要小心),如果你只想像Rack::Lock#call那样锁定它是首选以确保不会同时执行相同代码的两个实例。
此外,为了记录,每个请求在每个请求周期中创建和取消引用一个控制器。没有两个请求应该看到同一个实例,尽管它们可能看到同一个类。
设置config.threadsafe! 使我所说的几乎所有内容都无效。这会从堆栈中删除 Rack::Lock,这意味着您需要手动设置互斥锁以防止重复输入。除非你有充分的理由,否则不要这样做。
即使没有Rack::Lock,您仍然会在每个请求中获得一个控制器实例。控制器的入口点确保 notice the call to new in process.
【讨论】:
我的理解是每个控制器处理的 HTTP 请求都会创建一个新的控制器实例。
【讨论】:
Ruby 是单线程的。所以在任何时候,控制器一次只能处理一个请求。如果有多个请求,则将这些请求排队。为了避免这种情况,人们通常会运行一小组 Mongrel 以获得良好的并发性。它是这样工作的(直接来自 Mongrel WIKI FAQ):
Mongrel 然后获取这个 StringIO 输出、任何输出标头,并将它们以超快的速度流回客户端。
注意,如果页面被缓存,如果没有锁定。
【讨论】: