2011-06-08 63 views
44

Sinatra是多线程的吗?我读过其他地方,“sinatra默认为多线程”,这意味着什么?Sinatra是多线程的吗?

考虑这个例子

get "/multithread" do 
    t1 = Thread.new{ 
    puts "sleeping for 10 sec" 
    sleep 10 
    # Actually make a call to Third party API using HTTP NET or whatever. 
    } 
    t1.join 
    "multi thread" 
end 

get "/dummy" do 
    "dummy" 
end 

如果我进入“/多线程”,随后在另一个选项卡或浏览器则没有什么可以送达(在这种情况下,10秒)“/假的”,直到“/多线程”请求已完成。如果活动冻结应用程序变得无法响应。

我们如何解决这个问题而不会产生另一个应用程序实例?

+1

当然,你不能继续,因为'.join'会阻塞,直到每个线程完成 - 请参阅:http://ruby-doc.org/core-1.9/classes/Thread.html#M001331 – asaaki 2011-06-08 13:01:03

+0

那么这就是例子,实际上我可能正在使用HTTP Net进行读取文件或URI的调用,而不是专门在线程内进行读取。如果我不希望其他请求被阻止,那么我的工作是什么? – ch4nd4n 2011-06-08 13:16:06

+3

没有产生更多的实例,我看不到任何简单的解决方案。通常你会使用瘦或独角兽来拥有多个实例。如果你只想在后台做一些工作(所以不需要立即显示调用外部资源的结果),你应该真的使用后台作业(resque,延迟作业等),以及如果这些工作完成,可以在进一步的请求中显示结果。一般的问题是,在大多数情况下,Ruby应用程序不可能是真正的多线程,因为MRI还不支持多核。产卵/分叉是一种解决方法。 – asaaki 2011-06-08 15:34:14

回答

91

tl; dr Sinatra可以很好地处理线程,但是您可能需要使用不同的Web服务器。

Sinatra本身并没有施加任何并发模型,它甚至不处理并发。这由Rack handler(网络服务器)完成,如Thin,WEBrick或Passenger。 Sinatra本身是线程安全的,这意味着如果您的机架处理程序使用多个线程来处理服务器请求,它就可以正常工作。但是,由于Ruby 1.8只支持绿色线程,而Ruby 1.9具有全局VM锁定,所以线程并不广泛用于并发,因为在这两个版本上,线程并不会真正并行运行。但是,在JRuby或即将推出的Rubinius 2.0(两种可选的Ruby实现)上的意愿。

使用线程的大多数现有Rack处理程序都将使用线程池来重用线程,而不是为每个传入请求实际创建线程,因为线程创建不是免费的,尤其是,在1.9线程映射1:1到本地线程。绿线的开销要小得多,这就是为什么如上所述的Sinatra-synchrony所使用的基本上是合作安排的绿线的光纤最近变得如此受欢迎。您应该知道,任何网络通信都必须通过EventMachine,因此您不能使用例如mysql gem与您的数据库进行通信。

纤维可以很好地适合网络密集处理,但对于繁重的计算而言很失败。如果您使用光纤,您不太可能遇到竞争条件,这是常见的并发问题,因为它们只能在明确定义的点上执行上下文切换(无论何时等待IO),都会发生同步。还有第三种常见的并发模型:进程。您可以使用preforking服务器或自己启动多个进程。虽然这乍一看似乎是个不错的主意,但它有一些优点:在普通的Ruby实现上,这是同时使用所有CPU的唯一方法。而且你避免共享状态,所以根据定义没有竞争条件。而且,多进程应用可以轻松扩展到多台机器。请记住,您可以将多个进程与其他并发模型(均匀,合作,抢占)结合起来。

的选择主要取决于你使用的服务器和中间件提出:

  • 多进程,非preforking:杂种,薄,使用WEBrick,Zbatery
  • 多进程,preforking:独角兽,彩虹,乘客
  • 事件触发(适合西纳特拉-同步):薄,彩虹,Zbatery
  • 螺纹:净:: HTTP ::服务器,有螺纹的Mongrel,彪马,彩虹,Zbatery,薄型[1],Phusion Passenger Enterprise >= 4

[1]自从Sinatra 1.3.0开始,Thin将以线程模式启动,如果它是由Sinatra启动的(即,与ruby app.rb,但不是与thin命令,也不与rackup)。

+0

感谢你弄清楚事情。对不同模型的好解释。就像您在第三段中提到的,流程是一个很好的解决方案,我认为它被广泛用于扩展应用程序。 /子问题:你更喜欢哪种设置? – asaaki 2011-06-08 18:15:55

+0

感谢Konstantin的阐述。 – ch4nd4n 2011-06-09 04:46:59

+0

我通常更喜欢preforking,如果它适合基础设施,使用IO(使用回调,而不是光纤)。我对回调没有任何问题,并且在em-synchrony/sinatra-synchrony中看不到真正的优势,因为它们没有实现透明的期货/承诺。但是,这只是我,我猜。 – 2011-06-09 07:18:26

7

虽然周围的Googling,发现这种宝石:

sinatra-synchrony

这可能会帮助你,因为它触及你的问题。

还有一个基准,他们做了几乎相同的事情,就像你想(外部电话)。

结论:EventMachine就是这里的答案!

+1

我也做了基准测试。我的结果是26.6秒没有和Sinatra-synchrony宝石4.4秒 - 这是16倍快! – asaaki 2011-06-08 15:55:46

+0

我会试试这个,并希望能更新你们。谢谢。 – ch4nd4n 2011-06-09 04:47:48

+0

这是4年后,似乎作者现在讨厌EventMachine:https://github.com/kyledrake/sinatra-synchrony – 2015-01-28 04:56:49

1

对代码进行了一些更改后,我能够在mizuno 上运行padrino/sinatra应用程序。最初我试图在jRuby上运行Padrino应用程序,但它太简单了,我没有调查为什么。在jRuby上运行时,我正面临JVM崩溃。我还通过了this文章,这让我想到为什么即使选择Ruby,如果部署可以非常简单。

有没有关于在ruby中部署应用程序的讨论?或者我可以产生一个新的线程:)

1

我最近一直在JRuby自己,我非常惊讶从MRI切换到JRuby是多么简单。它几乎涉及淘汰一些宝石(在大多数情况下)。

您应该看看JRuby和Trinidad(App Server)的组合。 Torquebox也似乎是一个有趣的一体化解决方案,它不仅仅是一个应用服务器。

如果您想要支持线程的应用服务器,并且您熟悉Mongrel,Thin,Unicorn等,那么Trinidad可能是最容易迁移的,因为它与用户的角度几乎完全相同。爱它到目前为止!

+0

我终于明白了。默认情况下,thin是单线程的,您需要在启动应用程序时启用线程模式。 – ch4nd4n 2011-09-12 10:06:55

+0

我认为在Thin中穿线是实验性的。我记得有人提到,以这种方式使用Thin并不是一个好主意,因为它是一个平坦的应用服务器。然而,最近Puma 1.0.0发布了,现在这应该是一个有趣的选择。它比Trinidad/TorqueBox要低很多,对Rubyists来说应该非常熟悉。此外,它还可以与MRI,JRuby和Rubinius一起使用,但您当然可以通过使用允许像JRuby和Rubinius这样的真正线程的Ruby实现来获取大部分内容。 – 2012-04-01 10:40:19

4

想到我可能会为遇到此问题的人详细说明。西纳特拉包括代码这个小块:

server.threaded = settings.threaded if server.respond_to? :threaded=  

西纳特拉会检测你所安装的宝石的网络服务器(又名薄,彪马,等等。),如果响应“线程”,将它设置成拧如果要求。整齐。