ruby'async / io'和Reactor,有助于理解示例

时间:2018-11-23 11:46:21

标签: ruby async-await reactor tcpsocket

在了解here给出的基本“异步/ io”示例时,我需要一些帮助:

require 'async/io'

def echo_server(endpoint)
    Async::Reactor.run do |task|
        # This is a synchronous block within the current task:
        endpoint.accept do |client|
            # This is an asynchronous block within the current reactor:
            data = client.read(512)

            # This produces out-of-order responses.
            task.sleep(rand * 0.01)

            client.write(data.reverse)
        end
    end
end

def echo_client(endpoint, data)
    Async::Reactor.run do |task|
        endpoint.connect do |peer|
            result = peer.write(data)

            message = peer.read(512)

            puts "Sent #{data}, got response: #{message}"
        end
    end
end

Async::Reactor.run do
    endpoint = Async::IO::Endpoint.tcp('0.0.0.0', 9000)

    server = echo_server(endpoint)

    5.times.collect do |i|
        echo_client(endpoint, "Hello World #{i}")
    end.each(&:wait)

    server.stop
end

反应堆模式(正确的话,如果错误的话,请改正)基本上是同步任务的调度程序,例如,在阻塞时,一个任务被挂起,另一个任务被启动,依此类推,并且一旦任务被执行,任务又被恢复。畅通无阻的[source]

在给定的github示例中,首先定义了返回Async::Task的echo_server方法,并将其分配给服务器变量 server

现在已创建变量,基础任务开始在套接字上侦听并被client.read(512)调用阻塞。它被挂起,流到达循环部分,其中5个客户端Async::Task一对一地向套接字写入消息。

现在发生了我不了解的事情。服务器任务被解锁并回复第一条消息。在那之后它应该退出,因为没有任何循环。但是,它可以处理所有五个请求,然后退出。显然我出了点问题,但是我无法弄清楚。任何评论都将受到高度赞赏。

1 个答案:

答案 0 :(得分:0)

从循环中调用

echo_client会执行5次。该函数调用endpoint.connect并发送一条消息并读取一条响应。

echo_server被执行1次并调用endpoint.accept,这将为每个连接产生一个块。服务器读取一条消息并将其写回。

  

服务器任务被解锁并回复第一条消息。之后,应该退出,因为没有任何循环。

endpoint.accept被实现为a loop

        def accept(backlog = Socket::SOMAXCONN, &block)
            bind do |server|
                server.listen(backlog)

                server.accept_each(&block)
            end
        end

这里是implementation of server.accept_each

        def accept_each(task: Task.current)
            task.annotate "accepting connections #{self.local_address.inspect}"

            while true
                self.accept(task: task) do |io, address|
                    yield io, address, task: task
                end
            end
        end

如您所见,它绑定到套接字,侦听传入的连接,然后在循环中调用accept。