任何人都可以解释为什么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:明显的解决方法是将redis代码包装在EventMachine :: Synchrony.next_tick中,如issue #59暗示的那样,但考虑到EM.synchrony,我希望已经将调用包含在Fiber ...中/ p> PPS:同样适用于使用EM::Synchrony::Iterator
答案 0 :(得分:4)
你在这里做了一些相当棘手的事情..你正在为start_server提供一个块,它有效地创建了一个“匿名”连接类,并在该类的post_init方法中执行你的块。然后在该类中定义一个实例方法。
要记住的是:当reactor执行回调或者像receive_data这样的方法时,主线程(以及根光纤内)会发生这种情况,这就是为什么你会看到这个异常的原因。要解决此问题,您需要将每个回调包装在Fiber中执行(例如,请参阅Synchrony.add_(periodic)_timer方法)。
解决实际异常问题:在光纤中包装receive_data的执行。外部EM.synchrony {}对于稍后由反应堆安排的回调不会做任何事情。