以下是我的赛璐珞代码。
client1.rb
2个客户中的一个。 (我把它命名为客户1)
client2.rb
2个客户中的第2个。 (命名为客户2)
上述2个客户端之间唯一的区别是传递给服务器的文本。,分别是'client-1'
和'client-2'
对这两个客户端(通过并排运行)对下面两台服务器(一次一台)进行测试。我发现非常奇怪的结果。
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
将此作为上述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
我多次运行上述测试都导致了相同的行为。
任何人都可以从上述测试的结果中解释我。
问题:为什么赛璐珞会在处理其他请求之前等待60秒,如在server2.rb情况下注意到的那样。?
ruby -v
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]
答案 0 :(得分:6)
使用您的要点,我确认此问题可以在MRI 2.2.1
以及jRuby 1.7.21
和Rubinius 2.5.8
中重现... server1.rb
和{{1}之间的区别在后者中使用server2.rb
和DisplayMessage
类方法。
message
中使用sleep
超出DisplayMessage
范围。在Celluloid
中使用sleep
时,它实际上正在使用server1.rb
,但在Celluloid.sleep
中使用时,它正在使用server2.rb
...将Kernel.sleep
的邮箱向上,直到60秒过去。这可以防止将来处理该actor的方法调用,直到邮箱再次处理消息(对actor的方法调用)。
使用defer {}
或Server
阻止。
明确调用Celluloid.sleep
而不是future {}
(如果没有明确调用sleep
,则使用Celluloid.sleep
将最终调用sleep
,因为{{ 1}}不像Kernel.sleep
那样DisplayMessage
将include Celluloid
的内容带入Server
DisplayMessage.message
;或至少handle_message
范围内的server1.rb
,并使用正确的sleep
。
Server
方法:Celluloid
defer {}
方法:def handle_message(message)
defer {
DisplayMessage.message(message)
}
end
重申一下,更深层次的问题不是Celluloid.sleep
的范围......这就是为什么class DisplayMessage
def self.message(message)
#de ...
Celluloid.sleep 60
end
end
和sleep
是我最好的建议。但是在我的评论中发布一些内容:
使用defer
或future
推送一个任务,该任务会导致actor绑定到另一个线程。如果您使用defer
,则可以在任务完成后获得返回值,如果您使用future
则可以触发&忘记。
但更好的是,为那些倾向于被束缚的任务创建另一个角色,甚至将其他演员聚集在一起......如果future
或defer
不适合你。< / p>
我非常乐意回答这个问题提出的后续问题;我们有一个非常active mailing list和IRC频道。你慷慨的赏金是值得称道的,但是我们很多人会纯粹帮助你。
答案 1 :(得分:3)
<子>
管理以重现并修复问题。
删除我以前的答案。
显然,问题在于sleep
。
通过将日志"actor/kernel sleeping"
添加到Celluloids.rb's sleep()
的本地副本确认。
子>
在server1.rb
,
对
sleep
的调用在server
范围内 - 包含赛璐珞的类。因此,赛璐珞的
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.rb
。记录已添加到Celluloids.rb's sleep()
这仅暂停Celluloid中的当前“演员” 即只有处理client1的当前“Celluloid线程”才会休眠。
在server2.rb
,
对
sleep
的调用属于不包含赛璐珞的不同类DisplayMessage
。因此它本身就是
sleep
本身。
class DisplayMessage
def self.message(message)
...
sleep 60
end
end
请注意来自actor sleeping
的任何server2.rb
日志的缺席。
这会挂起当前的ruby任务,即ruby服务器休眠(不只是一个Celluloid actor)。
在
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