有人可以向我解释为什么Redis(redis-rb)同步驱动程序直接在EM.synchrony块下工作而在EM:Connection内不工作吗?
考虑以下示例
EM.synchrony do
redis = Redis.new(:path => "/usr/local/var/redis.sock")
id = redis.incr "local:id_counter"
puts id
EM.start_server('0.0.0.0', 9999) do |c|
def c.receive_data(data)
redis = Redis.new(:path => "/usr/local/var/redis.sock")
puts redis.incr "local:id_counter"
end
end
end
我越来越
can't yield from root fiber (FiberError)
在
receive_data
中使用时。通过阅读EventMachine和em-synchrony的源代码,我不知道有什么区别。谢谢!
PS:明显的解决方法是按照issue #59的提示将Redis代码包装在EventMachine::Synchrony.next_tick中,但是鉴于EM.synchrony,我希望已经将调用包装在Fiber中...
PPS:同样适用于
EM::Synchrony::Iterator
最佳答案
您在这里做了一些相当棘手的事情。您正在向start_server提供一个块,该块将有效地创建一个“匿名”连接类,并在该类的post_init方法中执行您的块。然后在该类中定义一个实例方法。
要记住的事情是:当反应堆执行回调或类似receive_data的方法时,它发生在主线程上(以及根光纤内),这就是为什么看到此异常的原因。要解决此问题,您需要将每个回调包装在Fiber中执行(例如,请参见Synchrony.add_(periodic)_timer方法)。
要解决您的实际异常,请在Fiber中包装对receive_data的执行。外部EM.synchrony {}不会对反应堆稍后计划的回调做任何事情。