单线程仍然处理并发请求?

Ruby进程是单线程。 当我们使用瘦服务器启动单个进程时,为什么我们仍然能够处理并发请求?

require 'sinatra' require 'thin' set :server, %w[thin] get '/test' do sleep 2 <---- "success" end 

什么是瘦内部可以处理并发请求? 如果是由于事件 – 机器框架,上面的代码实际上是一个不用于EM的同步代码。

引用章节: http : //merbist.com/2011/02/22/concurrency-in-ruby-explained/中的 “非阻塞IO /反应器模式”“这是Twisted,EventMachine和Node.js使用的方法Ruby开发人员可以使用EventMachine或基于EventMachine的Web服务器(如Thin)以及EM客户端/驱动程序来进行非阻塞异步调用。“

事情的核心是EventMachine.defer *用于将阻塞操作集成到EventMachine的控制流中。 defer的操作是获取第一个参数(“operation”)中指定的块,并将其安排在EventMachine维护的内部线程池上进行异步执行。

当操作完成时,它会将块(如果有)计算的结果传递回EventMachine反应器。 然后,EventMachine调用第二个参数中指定的块来推迟(“回调”),作为其正常事件处理循环的一部分。

由操作块计算的结果作为参数传递给回调。 如果在操作完成后不需要执行任何代码,则可以省略回调参数。 *

本质上,响应HTTP请求,服务器执行您编写的,调用Connecction类中的process方法。 看看$GEM_HOME/gems/thin-1.6.2/lib/thin/connection.rb

 # Connection between the server and client. # This class is instanciated by EventMachine on each new connection # that is opened. class Connection < EventMachine::Connection 
 # Called when all data was received and the request # is ready to be processed. def process if threaded? @request.threaded = true EventMachine.defer(method(:pre_process), method(:post_process)) else @request.threaded = false post_process(pre_process) end end 

..这是一个线程连接调用EventMachine.defer

反应堆

要查看激活的位置, EventMachine反应器应该遵循程序的初始化:请注意,对于所有Sinatra应用程序和中间件( $GEM_HOME/gems/sinatra-1.4.5/base.rb ),可以将Sinatra应用程序作为自托管运行服务器使用Thin,Puma,Mongrel或WEBrick。

  def run!(options = {}, &block) return if running? set options handler = detect_rack_handler .... 

方法detect_rack_handler返回第一个Rack :: Handler

  return Rack::Handler.get(server_name.to_s) 

在我们的测试中,我们需要瘦,因此它返回一个Thin机架处理程序并设置一个线程服务器

  # Starts the server by running the Rack Handler. def start_server(handler, server_settings, handler_name) handler.run(self, server_settings) do |server| .... server.threaded = settings.threaded if server.respond_to? :threaded= 

$GEM_HOME/gems/thin-1.6.2/lib/thin/server.rb

 # Start the server and listen for connections. def start raise ArgumentError, 'app required' unless @app log_info "Thin web server (v#{VERSION::STRING} codename #{VERSION::CODENAME})" ... log_info "Listening on #{@backend}, CTRL+C to stop" @backend.start { setup_signals if @setup_signals } end 

$GEM_HOME/gems/thin-1.6.2/lib/thin/backends/base.rb

  # Start the backend and connect it. def start @stopping = false starter = proc do connect yield if block_given? @running = true end # Allow for early run up of eventmachine. if EventMachine.reactor_running? starter.call else @started_reactor = true EventMachine.run(&starter) end end