ruby 'async / io' и Reactor, помогите понять пример - PullRequest
0 голосов
/ 23 ноября 2018

Мне нужна помощь в понимании базового примера 'async / 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

Схема реактора (исправьте, пожалуйста, если не так) в основном является своего рода планировщикомсинхронные задачи, такие, что после блокировки задача приостанавливается, а другая запускается и т. д., и, в свою очередь, задачи возобновляются после разблокирования их работы [источник]

ВВ приведенном примере с github сначала определяется метод echo_server, возвращающий Async::Task, и назначается серверной переменной server

Теперь, когда переменная создана, базовая задача начинает прослушивать сокет и блокируется.по телефону client.read(512).Это приостановлено, и поток достигает части цикла, где 5 клиентов Async::Task s записывают сообщения в сокет один за другим.

А теперь происходит то, чего я не понимаю.Задача сервера разблокируется и отвечает на первое сообщение.После этого он должен выйти, потому что петли нет.Однако он обслуживает все пять запросов и выходит после этого.Очевидно, что-то я ошибаюсь, но я не могу понять это.Любые комментарии высоко ценятся.

1 Ответ

0 голосов
/ 03 января 2019

echo_client выполняется 5 раз, так как он вызывается из цикла.Эта функция вызывает endpoint.connect, отправляет одно сообщение и читает один ответ.

echo_server выполняется 1 раз и вызывает endpoint.accept, что дает блок для каждого соединения.Сервер читает одно сообщение и записывает его обратно.

Задача сервера разблокируется и отвечает на первое сообщение.После этого он должен выйти, потому что цикл не существует.

endpoint.accept реализован как цикл :

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

                server.accept_each(&block)
            end
        end

Вот реализация 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.

...