2011-06-08 60 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=  

西納特拉會檢測你所安裝的寶石的網絡服務器(又名薄,彪馬,等等。),如果響應「線程」,將它設置成擰如果要求。整齊。