有人可以向我解释为什么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 {}不会对反应堆稍后计划的回调做任何事情。

10-08 04:21