web-dev-qa-db-ja.com

シナトラはマルチスレッドですか?

シナトラはマルチスレッドですか? 「シナトラはデフォルトでマルチスレッド化されている」という他の記事を読みましたが、それはどういう意味ですか?

この例を考えてみましょう

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

その後別のタブまたはブラウザで「/ multithread」と「/ dummy」にアクセスすると、「/ multithread」リクエストが完了するまで、何も(この場合は10秒間)何も処理されません。アクティビティがフリーズした場合、アプリケーションが応答しなくなります。

アプリケーションの別のインスタンスを生成せずにこれを回避するにはどうすればよいですか?

46
ch4nd4n

tl; drシナトラはスレッドでうまく機能しますが、おそらく別のWebサーバーを使用する必要があります。

Sinatra自体は並行性モデルを強制せず、並行性も処理しません。これは、Thin、WEBrick、Passengerなどのラックハンドラー(Webサーバー)によって行われます。 Sinatra自体はスレッドセーフです。つまり、Rackハンドラーがサーバーリクエストに複数のスレッドを使用する場合、それは問題なく機能します。ただし、Ruby 1.8はグリーンスレッドのみをサポートし、Ruby 1.9はグローバルVMロックを持っているため、スレッドはそれほど広くありません。同時実行に使用されます。これは、両方のバージョンでスレッドが完全に並列に実行されるわけではないためですが、JRubyまたは今後のRubinius 2.0(両方の代替Ruby実装))では実行されます。

スレッドの作成は無料ではないため、着信リクエストごとに実際にスレッドを作成する代わりに、スレッドを使用する既存のほとんどのラックハンドラーはスレッドプールを使用してスレッドを再利用します。 1.9では、スレッドは1:1でネイティブスレッドにマッピングされます。グリーンスレッドはオーバーヘッドがはるかに少ないため、上記のシナトラ同期で使用される、基本的に協調的にスケジュールされたグリーンスレッドであるファイバーが最近非常に一般的になりました。ネットワーク通信はすべてEventMachineを経由する必要があるため、たとえばmysql gemを使用してデータベースと通信することはできないことに注意してください。

ファイバーは、ネットワークの集中的な処理には適切にスケーリングしますが、大量の計算には失敗します。ファイバーを使用すると、明確に定義されたポイントでのみコンテキストスイッチが実行されるため(IOを待機するたびに同期が行われるため)、競合状態に陥る可能性が低くなります。 3つ目の一般的な同時実行モデルとして、プロセスがあります。プリフォークサーバーを使用するか、複数のプロセスを自分で起動できます。これは一見悪い考えのように見えますが、いくつかの利点があります。通常のRuby実装では、これはすべてのCPUを同時に使用する唯一の方法です。共有状態を避けるため、また、マルチプロセスアプリは複数のマシンで簡単にスケーリングできます。複数のプロセスを他の同時実行モデル(イベント、協調、プリエンプティブ)と組み合わせることができることに注意してください。

選択は主に、使用するサーバーとミドルウェアによって行われます。

  • マルチプロセス、非プリフォーク:Mongrel、Thin、WEBrick、Zbatery
  • マルチプロセス、プリフォーク:ユニコーン、レインボー、乗客
  • イベント(シナトラ同期に適しています):Thin、Rainbows、Zbatery
  • スレッド:Net :: HTTP :: Server、スレッドMongrel、Puma、Rainbows、Zbatery、Thin [1]、 Phusion Passenger Enterprise> = 4

[1] Sinatra 1.3.0以降、Sinatraによって起動された場合、Thinはスレッドモードで起動されます(つまり、Ruby app.rb、ただしthinコマンドやrackupは使用できません)。

91

ぐるぐる回っているときに、この宝石を見つけました:

シナトラ同期

それはあなたの質問に触れるので、あなたを助けるかもしれません。

ベンチマークもあり、彼らはあなたが望むようにほとんど同じことをしました(外部呼び出し)。

結論:EventMachineがここでの答えです!

6
asaaki

これに出くわした人のために詳しく説明すると思います。シナトラには、次の小さなコードが含まれています。

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

Sinatraは、Webサーバーにインストールしたgem(別名、thin、pumaなど)を検出し、「threaded」に応答する場合は、要求された場合にそれをスレッド化するように設定します。きちんと。

4
Joel Jackson

私は最近自分でJRubyにアクセスしており、MRIからJRubyに切り替えるのがいかに簡単であるかに非常に驚いています。ほとんどの場合、いくつかの宝石を交換する必要があります。

JRubyとTrinidad(App Server)の組み合わせを確認する必要があります。 Torqueboxはまた、興味深いオールインワンソリューションであるように見えます。それは、単なるアプリサーバーだけではありません。

スレッドをサポートするアプリサーバーが必要で、Mongrel、Thin、Unicornなどに精通している場合は、ユーザーの観点から見るとほとんど同じなので、トリニダードはおそらく最も簡単に移行できます。これまで愛してる!

1

コードにいくつかの変更を加えた後、 mizuno でpadrino/sinatraアプリケーションを実行することができました。最初、私はjRubyでPadrinoアプリケーションを実行しようとしましたが、それは単に不安定すぎて、理由については調べませんでした。 jRubyで実行しているときにJVMのクラッシュに直面していました。私は this の記事も読んだので、展開が簡単ではない場合にRubyを選択するのはなぜですか?.

Rubyでのアプリケーションのデプロイメントについての議論はありますか?または、私は新しいスレッドを生成することができます:)

1
ch4nd4n