10

以下は私のセルロイドコードです。

  1. client1.rb2 クライアントのうちの 1 つ。(クライアント1と名付けました)

  2. client2.rb2 クライアントの 2 番目。(クライアント 2 と命名)

ノート:

上記の 2 つのクライアントの唯一の違いは、サーバーに渡されるテキストです。すなわち('client-1'および'client-2'それぞれ)

次の 2 つのサーバー (一度に 1 つ) に対して、この 2 つのクライアントを (並べて実行して) テストします。非常に奇妙な結果が見つかりました。

  1. server1.rb( celluloid-zmq の README.md から取られた基本的な例)

    これを上記の 2 つのクライアントのサンプル サーバーとして使用すると、タスクが並列実行されます。

出力

ruby server1.rb

Received at 04:59:39 PM and message is client-1
Going to sleep now
Received at 04:59:52 PM and message is client-2

ノート:

client1.rbリクエストがスリープ状態のときに client2.rb メッセージが処理されました。(並列処理マーク)

  1. server2.rb

    これを上記の 2 つのクライアントのサンプル サーバーとして使用しても、タスクの並列実行は発生しませんでした。

出力

ruby server2.rb

Received at 04:55:52 PM and message is client-1
Going to sleep now
Received at 04:56:52 PM and message is client-2

ノート:

クライアント 2は、クライアント 1がスリープ状態になって から 60 秒間待機するように求められました(60 秒間スリープ)

上記のテストを複数回実行しましたが、すべて同じ動作になりました。

上記のテストの結果から、誰でも説明できますか。

質問:他のリクエストを処理する前にセルロイドが 60 秒間待たされるのはなぜですか?

ルビー版

ruby -v

ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]

4

2 に答える 2

3

問題を再現して修正することができました。以前の回答を削除します。どうやら、問題は にありますsleepCelluloids.rb の"actor/kernel sleeping"ローカル コピーにログを追加して確認しました。sleep()


ではserver1.rb

への呼び出しsleepserverは、Celluloid を含むクラス内にあります。

したがって、Celluloid の の実装はsleep、ネイティブの をオーバーライドしますsleep

class Server
  include Celluloid::ZMQ

  ...

  def run
    loop { async.handle_message @socket.read }
  end

  def handle_message(message)

        ...

        sleep 60
  end
end

actor sleepingからのログに注意してくださいserver1.rbCelluloids.rbに追加されたログsleep()

これは、Celluloid の現在の「アクター」のみを一時停止します。つまり、client1 を処理している現在の「Celluloid スレッド」のみがスリープします。


ではserver2.rb

への呼び出しsleepDisplayMessageは、Celluloid を含まない別のクラス内にあります。

したがって、それはネイティブsleepそのものです。

class DisplayMessage
    def self.message(message)

           ...

           sleep 60
    end
end

actor sleepingからのログがないことに注意してくださいserver2.rb

これにより、現在の ruby​​ タスクが中断されます。つまり、ruby サーバーがスリープ状態になります (単一の Celluloid アクターだけではありません)。


修正?

ではserver2.rb、適切なsleepを明示的に指定する必要があります。

class DisplayMessage
    def self.message(message)
        puts "Received at #{Time.now.strftime('%I:%M:%S %p')} and message is #{message}"
        ## Intentionally added sleep to test whether Celluloid block the main process for 60 seconds or not.
        if message == 'client-1'
           puts 'Going to sleep now'.red

           # "sleep 60" will invoke the native sleep.
           # Use Celluloid.sleep to support concurrent execution
           Celluloid.sleep 60
        end
    end
end
于 2016-01-30T18:12:13.253 に答える