Ruby进程是单线程。当我们使用瘦服务器启动单个进程时,为什么我们仍然能够处理并发请求?
require 'sinatra'
require 'thin'
set :server, %w[thin]
get '/test' do
sleep 2 <----
"success"
end
什么是可以处理并发请求的内部瘦身?如果是由于事件 - 机器框架,上面的代码实际上是一个不用于EM的同步代码。
答案 0 :(得分:2)
引用章节:&#34;非阻塞IO /反应堆模式&#34; in http://merbist.com/2011/02/22/concurrency-in-ruby-explained/: &#34;这是Twisted,EventMachine和Node.js使用的方法。 Ruby开发人员可以使用EventMachine或 基于EventMachine的Web服务器,如Thin以及EM客户端/驱动程序,可以进行非阻塞异步调用。&#34;
问题的核心是EventMachine.defer * 用于将阻塞操作集成到EventMachine的控制流程中。 延迟的动作是取第一个参数中指定的块(&#34;操作&#34;) 并安排它在EventMachine维护的内部线程池上进行异步执行。
当操作完成时,它将传递块计算的结果(如果有的话) 回到EventMachine反应堆。 然后,EventMachine调用第二个参数中指定的块来推迟(&#34;回调&#34;), 作为其正常事件处理循环的一部分。
操作块计算的结果作为参数传递给回调。 如果在操作完成后不需要执行任何代码,则可以省略回调参数。 *
基本上,在响应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 reactor的激活位置
应该遵循程序的初始化:
请注意,对于所有Sinatra应用程序和中间件($GEM_HOME/gems/sinatra-1.4.5/base.rb
)
可以使用Thin,Puma,Mongrel或WEBrick将Sinatra应用程序作为自托管服务器运行。
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 ,因此它返回一个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