Prepare for the test: sleep 10
in a action
Test: Open two tabs in the browser to visit the action
Result: When the second request is running, the first request finished and began rendering the view, but the view is still blank. After the second request finished too, the two requests finished rendering the view at the same time.
Conclusion: Rails is just one single instance. One request can only enter the action after the previous requests finish. But how to explain the response part? Why the multi-requests finish rendering the views at the same time?
Rails automatically allows various operations to be performed at the same time. When using a threaded web server, such as the default Puma, multiple HTTP requests will be served simultaneously, with each request provided its own controller instance.
We see in Round 14, the common Rails setup (puma-mri-rails) generates 531 requests per second, while Roda, an extremely lightweight Ruby web framework, in combination with Sequel, generates about 7000 requests per second. Finally, we may ask the same question as after the first experiment.
Even if the request made from a new tab by the same user, the web server starts a new thread. (That is generally speaking. Although some imaginary server can perform them in queue in a single thread, but usually they are multithreaded and do not care about users) So, requests are performed simultaneously.
Usually, each of the users sends an HTTP request for the page. The server receives the requests and delegates them to different workers (processes or threads). Depending on the URL given, the server reads a file and sends it back to the user.
WEBrick is multi-threaded but Rails developers hard-coded a mutex, so it can handle just one request at a time. You can monkey-patch Rails::Server
and you are free to run a multi-threaded WEBrick.
Just note that WEBrick will be multithreaded only when config config.cache_classes = true
and config.eager_load = true
, which is typical to RAILS_ENV=production
. This is because class reloading in development is not thread safe.
To get WEBrick fully multi-threaded in Rails 4.0, just add this to 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
The offending code in rails/commands/server.rb
that we got rid of is:
# 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
It's not needed on Rails 4.2. It's concurrent out-of-the-box.
Are you using a WEBrick
server? That must be because your server is a single threaded server and is capable of fulfilling one request at a time (because of the single worker thread). Now in case of multiple requests, it runs the action part of the request and before running the view renderer it checks to see if there are any pending requests. Now if 10 requests are lined up, it would first complete all of them before actually rendering the views. When all of these requests are completed, the views would now be rendered sequentially.
You can switch to Passenger or Unicorn server if you want multi-threaded environment.
Hope that makes sense.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With