Ruby 为什么Sinatra请求使用EM线程?
Sinatra应用程序接收长时间运行任务的请求,并将其推迟,在EM的20个线程的内部池中启动它们。当运行的EM.defer超过20个时,它们将由EM.defer存储在EM的threadqueue中 然而,似乎Sinatra不会为任何请求提供服务,直到有一个EM线程可以处理它们。我的问题是,难道Sinatra不应该使用主线程的反应器来服务所有请求吗?为什么我在发出新请求时在threadqueue上看到一个add 复制步骤: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
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不知道你的应用程序将要做什么或者需要多长时间。