1

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

然而,在有可用的 EM 线程处理它们之前,Sinatra 似乎不会为任何请求提供服务。我的问题是,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
4

2 回答 2

4

好的,所以 Sinatra 似乎默认以线程模式启动 Thin 导致上述行为。你可以加

set :threaded, false

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

来源1

来源2

于 2012-06-05T09:46:15.393 回答
0

除非我对您的问题有误解,否则这就是 EventMachine 的工作原理。如果您查看EM.defer 的文档,它们会声明:

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

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

如果您只需要更多线程,则可能会threadpool_size遇到问题,尽管最终这不是一个长期的解决方案。

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

于 2012-06-04T14:18:43.390 回答