Rails如何同时处理多个请求?

24

测试准备: 在一个操作中执行sleep 10

测试: 在浏览器中打开两个标签页以访问该操作

结果: 当第二个请求正在运行时,第一个请求已完成并开始渲染视图,但是视图仍然为空白。 在第二个请求也完成后,两个请求同时完成了视图的渲染。

结论: Rails只是一个单一的实例。一个请求只能在前面的请求完成后进入该操作。但如何解释响应部分呢?为什么多个请求可以同时完成视图的渲染呢?

3个回答

25

WEBrick是多线程的,但Rails开发人员硬编码了一个互斥锁,因此它只能一次处理一个请求。您可以猴子补丁Rails:: Server,然后您就可以自由运行多线程的WEBrick。

请注意,仅当配置config.cache_classes = true和config.eager_load = true时,WEBrick才会是多线程的,这通常是RAILS_ENV = production。这是因为在开发中重新加载类不是线程安全的。

要在Rails 4.0中完全实现WEBrick的多线程,请将以下内容添加到config/initializers/multithreaded_webrick.rb中:

# Remove Rack::Lock so WEBrick can be fully multi-threaded.
require 'rails/commands/server'

class Rails::Server
  def middleware
    middlewares = []
    middlewares << [Rails::Rack::Debugger] if options[:debugger]
    middlewares << [::Rack::ContentLength]

    Hash.new middlewares
  end
end

我们删掉的rails/commands/server.rb中的有问题的代码是:

# FIXME: add Rack::Lock in the case people are using webrick.
# This is to remain backwards compatible for those who are
# running webrick in production. We should consider removing this
# in development.
if server.name == 'Rack::Handler::WEBrick'
  middlewares << [::Rack::Lock]
end

在Rails 4.2上不需要它,因为它是开箱即用的并发。


1
@geekazoid,我猜是Rails 4.1吧?我只在Rails 4.0上进行了测试。我会看看如何在4.1中实现。 - Nowaker
Rails 4.2在RAILS_ENV=production环境下默认支持并发。 - Nowaker
@Matt,我手头没有任何Rails 4.1应用程序。你能否自己检查并告诉我? - Nowaker
2
或者在你的application.rb中添加config.middleware.delete 'Rack::Lock' - Benj
1
不错,初始化程序在Rails 4.2中解决了这个问题,我用“unless Rails.env.production?”条件包裹它,以便仅在测试和开发中执行。其他建议,如'config.middleware.delete ...'或'config.allow_concurrency...'没有帮助。 - januszm
显示剩余5条评论

5
您是否正在使用WEBrick服务器?这是因为您的服务器是单线程服务器,只能一次完成一个请求(因为只有一个工作线程)。现在,在多个请求的情况下,它运行请求的动作部分,并在运行视图渲染器之前检查是否有任何未处理的请求。如果有10个请求排队,它将首先完成所有这些请求,然后再实际呈现视图。当所有这些请求都完成时,视图现在将按顺序呈现。
如果您想要多线程环境,可以切换到Passenger或Unicorn服务器。
希望这样讲得清楚易懂。

谢谢,你让我少了些困惑。我同时测试了更多的请求,似乎在排队不到10个请求后,webrick会渲染视图,然后解决其他请求。 - Keating
我认为webrick不是单线程服务器,你可以在production.rb中设置'config.threadsafe!',然后它将同时处理多个请求。 - Keating
config.threadsafe! 不会自动使 WEBrick 多线程化。有关详细信息,请参阅我的答案。 - Nowaker
这个答案并不完全正确。Rails在渲染视图之前不仅会进行检查,还会在整个请求周围放置一个锁,其中包括处理请求和生成响应,这要归功于Rack::Lock。此外,Passenger或Unicorn不会生成线程,它们生成作为独立进程运行的工作进程。 - Emil

0
在您的环境设置config/environments/development.rb(或config/application.rb)中,
添加以下行:
  #Enable threaded mode
  config.threadsafe!

1
这个选项已经不再需要或支持(至少自Rails 4以来如此)。详情请参见http://tenderlovemaking.com/2012/06/18/removing-config-threadsafe.html。 - RobDil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接