rails控制器是多线程的吗?控制器中的Thread.exclusive

时间:2009-09-07 11:42:34

标签: ruby-on-rails ruby multithreading

Rails控制器是多线程的吗?

如果是这样,我可以通过简单地保护从多个线程运行的某段代码(每十分钟只触发一次)

require 'thread'
Thread.exclusive do
     # stuff here
end

on我需要以某种方式在监视器上同步吗?

3 个答案:

答案 0 :(得分:13)

在基本的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

...将确保块内的东西永远不会与任何其他代码并行运行。在所有线程之间创建共享Mutext(在类变量或其他东西中,但在开发模式下重新加载时可能会被擦除,所以要小心),并在Rack::Lock#call上锁定它是首选如果你只是想确保不会同时执行相同代码的两个实例。

此外,对于记录,每个请求在每个请求周期中创建和取消引用一个控制器。没有两个请求应该看到相同的实例,尽管它们可能会看到相同的类。

设置config.threadsafe!几乎使我所说的一切都无效。这会从堆栈中删除Rack::Lock,这意味着您需要手动设置互斥锁以防止双重输入。除非你有充分的理由,否则不要这样做。

即使没有Rack::Lock,您仍会在每个请求中获得一个控制器实例。控制器的入口点确保notice the call to new in process.

答案 1 :(得分:1)

我的理解是为控制器处理的每个HTTP请求创建一个新的控制器实例。

答案 2 :(得分:1)

Ruby是单线程的。因此,在任何时候,控制器一次只能处理一个请求。如果有多个请求,则这些请求排队。为了避免这种情况,人们通常运行一小组Mongrels来获得良好的并发性。它的工作原理如下(直接来自Mongrel WIKI FAQ):

  1. 请求命中了mongrel。
  2. Mongrel创建一个线程并解析HTTP请求标头
  3. 如果身体很小,那么它将身体放入StringIO
  4. 如果身体很大,那么它会将身体流式传输到临时文件
  5. 当请求被“熟”时,它会调用RailsHandler。
  6. RailsHandler查看文件是否可能被页面缓存,如果是,则发送缓存页面。
  7. 现在你终于准备好处理Rails请求了。 LOCK!
  8. 仍然锁定,Mongrel调用Rails Dispatcher来处理请求,传入头文件,以及StringIO或Tempfile for body。
  9. 当Rails完成后,解锁! 。 Rails(希望)将其所有输出都放入StringIO中。
  10. 然后Mongrel获取此StringIO输出,任何输出标头,并将它们快速地流回客户端。

    请注意,如果页面被缓存,则没有锁定。