为什么Sinatra请求需要EM线程?

时间:2012-06-04 12:48:54

标签: ruby sinatra eventmachine

Sinatra应用程序接收长时间运行任务的请求,EM.defer它们,在EM的20个线程的内部池中启动它们。当EM.defer运行超过20个时,EM.defer会将它们存储在EM的线程序列中。

但是,似乎Sinatra不会为任何请求提供服务,直到有一个EM线程可以处理它们。我的问题是,是不是Sinatra假设使用主线程的反应器来服务所有请求?当我发出新请求时,为什么我会在线程上看到添加?

重现的步骤:

Access /track/
Launch 30 /sleep/ reqs to fill the threadqueue
Access /ping/ and notice the add in the threadqueue as well as the delay

重现它的代码:

require 'sinatra'
#monkeypatch EM so we can access threadpools
module EventMachine 
  def self.queuedDefers 
    @threadqueue==nil ? 0: @threadqueue.size 
  end
  def self.availThreads 
    @threadqueue==nil ? 0: @threadqueue.num_waiting
  end
  def self.busyThreads 
    @threadqueue==nil ? 0: @threadpool_size - @threadqueue.num_waiting
  end   
end 
get '/track/?' do
  EM.add_periodic_timer(1) do 
    p "Busy: " + EventMachine.busyThreads.to_s + "/" +EventMachine.threadpool_size.to_s + ", Available: " + EventMachine.availThreads.to_s + "/" +EventMachine.threadpool_size.to_s + ", Queued: " + EventMachine.queuedDefers.to_s 
  end 
end

get '/sleep/?' do
  EM.defer(Proc.new {sleep 20}, Proc.new {body "DONE"})
end

get '/ping/?' do
  body "pong"
end

我在Rack / Thin(没有Sinatra)上做了同样的事情并按照预期的方式工作,所以我猜Sinatra正在造成它。

Ruby version: 1.9.3.p125
EventMachine: 1.0.0.beta.4.1
Sinatra: 1.3.2
OS: Windows

2 个答案:

答案 0 :(得分:4)

好的,所以看起来Sinatra默认在线程模式下启动Thin会导致上述行为。 你可以添加

set :threaded, false

在您的Sinatra配置部分中,这将阻止Reactor在单独的线程上延迟请求,并在加载时阻止。

Source1

Source2

答案 1 :(得分:0)

除非我误解了你的问题,否则这几乎就是EventMachine的工作方式。如果您查看docs for EM.defer,则说明:

  

不要编写将永久阻止的延迟操作。如果是这样的话   当前实现不会检测到问题和线程   永远不会回到游泳池。 EventMachine限制了数量   池中的线程,所以如果你这么做,你的后续   延期的操作将无法运行。

基本上,有一定数量的线程,如果你使用它们,任何挂起的操作都会阻塞,直到一个线程可用。

如果您只需要更多线程,可能会碰到threadpool_size,但最终这不是一个长期解决方案。

关于Sinatra和线程,

Is Sinatra multi threaded?在这里是一个非常好的问题。简而言之,Sinatra非常棒,但如果你需要合适的线程,你可能需要寻找其他地方。