EM中的纤维:连接(em-synchrony)

3

请问有人能解释一下为什么 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中,如问题#59所示,但考虑到EM.synchrony,我希望已经在Fiber中包装了调用...

PPS:同样适用于使用EM :: Synchrony :: Iterator

1个回答

4
你正在进行一些相当棘手的操作。 你向start_server提供了一个块,这实际上创建了一个“匿名”的连接类,并在该类的post_init方法中执行你的块。 然后,在该类内部,你定义了一个实例方法。
需要记住的是:当反应器执行回调或像receive_data这样的方法时,它发生在主线程(和根纤维)中,这就是为什么你看到此异常的原因。 要解决这个问题,你需要将要执行的每个回调都包装在Fiber中(例如,参见Synchrony.add_(periodic)_timer方法)。
要解决实际的异常:将receive_data的执行包装在Fiber中。外部的EM.synchrony {}对于由反应器稍后调度的回调不起作用。

谢谢!这个块只是为了让代码示例保持简短,否则它就是一个普通的类。我错过的部分是“当反应器执行回调或像receive_data这样的方法时,它发生在主线程(以及根纤维内)”。我想我的思维太过专注于类似多线程的概念,当你在这种情况下自动获得一个新的(池化的)线程。 - Radim
@igrigorik你能提供一个例子吗?我也在遇到同样的问题。我应该将整个receive_data包装在Fiber中吗?我只想将数据保存在Redis中... - Dennis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接