为什么Sinatra请求采用EM线程?

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 

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

 set :threaded, false 

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

源1

源2

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

不要编写将永久阻止的延迟操作。 如果是这样,当前实现将不会检测到该问题,并且该线程将永远不会返回到池中。 EventMachine限制其池中的线程数,因此如果执行此操作的次数足够多,则后续的延迟操作将无法运行。

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

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

Sinatra是multithreading的吗? 关于Sinatra和线程,这是一个非常好的问题。 简而言之,Sinatra非常棒,但如果你需要合适的线程,你可能需要寻找其他地方。