Ruby 为什么Sinatra请求使用EM线程?

Ruby 为什么Sinatra请求使用EM线程?,ruby,sinatra,eventmachine,Ruby,Sinatra,Eventmachine,Sinatra应用程序接收长时间运行任务的请求,并将其推迟,在EM的20个线程的内部池中启动它们。当运行的EM.defer超过20个时,它们将由EM.defer存储在EM的threadqueue中 然而,似乎Sinatra不会为任何请求提供服务,直到有一个EM线程可以处理它们。我的问题是,难道Sinatra不应该使用主线程的反应器来服务所有请求吗?为什么我在发出新请求时在threadqueue上看到一个add 复制步骤: Access /track/ Launch 30 /sleep/ reqs

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

然而,似乎Sinatra不会为任何请求提供服务,直到有一个EM线程可以处理它们。我的问题是,难道Sinatra不应该使用主线程的反应器来服务所有请求吗?为什么我在发出新请求时在threadqueue上看到一个add

复制步骤:

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

除非我对你的问题有所误解,这就是EventMachine的工作原理。如果您签出,它们会声明:

不要编写会永远阻塞的延迟操作。若有,详情为何? 当前实现不会检测到问题,线程 永远不会被送回游泳池。EventMachine限制 线程池中的线程,因此如果您这样做的次数足够多,您的后续 延迟的操作将没有机会运行

基本上,线程的数量是有限的,如果用完了线程,任何挂起的操作都会阻塞,直到有一个线程可用为止

如果您只需要更多的线程,可能会增加
threadpool\u size
,尽管最终这不是一个长期的解决方案


关于Sinatra和threads,这是一个非常好的问题。简而言之,Sinatra非常棒,但是如果你需要合适的线程,你可能需要去别处看看。

除非我对你的问题有所误解,这就是EventMachine的工作原理。如果您签出,它们会声明:

不要编写会永远阻塞的延迟操作。若有,详情为何? 当前实现不会检测到问题,线程 永远不会被送回游泳池。EventMachine限制 线程池中的线程,因此如果您这样做的次数足够多,您的后续 延迟的操作将没有机会运行

基本上,线程的数量是有限的,如果用完了线程,任何挂起的操作都会阻塞,直到有一个线程可用为止

如果您只需要更多的线程,可能会增加
threadpool\u size
,尽管最终这不是一个长期的解决方案


关于Sinatra和threads,这是一个非常好的问题。简言之,Sinatra非常棒,但是如果你需要合适的线程,你可能需要去别处看看。

好的,所以Sinatra在默认情况下以线程模式启动,导致上述行为。 你可以加上

set :threaded, false
在Sinatra配置部分中,这将防止反应器延迟单独线程上的请求,并在负载下阻塞


好的,看来Sinatra在默认情况下以线程模式启动,导致上述行为。 你可以加上

set :threaded, false
在Sinatra配置部分中,这将防止反应器延迟单独线程上的请求,并在负载下阻塞


Muffinista,很清楚EventMachine是如何工作的。我的问题更多的是关于为什么Sinatra(在我的主线程上运行)不能在EM线程已满时为一个简单的请求提供服务。Sinatra不应该受到EM队列的影响,因为它在主线程上运行,从不阻塞。此外,没有任何迹象表明,为一个简单的get“/”body“pong”端提供服务会使EM.defer延迟一个新线程,但是上面的代码显示了这样的情况。您的示例实际上并没有为我运行,所以我无法进行测试,但如果我没有弄错的话,在您的场景中,EM.defer将为所有请求运行。这是有道理的——Sinatra不知道你的应用程序将要做什么,也不知道需要多长时间。Muffinista,很清楚EventMachine是如何工作的。我的问题更多的是关于为什么Sinatra(在我的主线程上运行)不能在EM线程已满时为一个简单的请求提供服务。Sinatra不应该受到EM队列的影响,因为它在主线程上运行,从不阻塞。此外,没有任何迹象表明,为一个简单的get“/”body“pong”端提供服务会使EM.defer延迟一个新线程,但是上面的代码显示了这样的情况。您的示例实际上并没有为我运行,所以我无法进行测试,但如果我没有弄错的话,在您的场景中,EM.defer将为所有请求运行。这是有道理的——Sinatra不知道你的应用程序将要做什么或者需要多长时间。