ruby 'async/io' and Reactor, help understand the example
I need some help in understanding basic 'async/io' example as given here:
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
A reactor pattern (correct please if wrong) is basically kind of scheduler of synchronous tasks, such that upon blocking, a task is suspended and another one is launched, and so on, and in turn tasks are resumed once their operation is unblocked [source]
In the given github example first the echo_server method returning Async::Task
is defined, and assigned to server variable server
Now that the variable is created, the underlying task starts listening on the socket and gets blocked by client.read(512)
call. It is suspended and the flow reaches the loop part where 5 client Async::Task
s one by one write messages to the socket.
And now happens something I don't understand. The server task gets unlocked and replies to the first message. After that it should quit, because there is no kind of loop. However it serves all five requests and quits after that. Obviously there is something I am getting wrong, but I cannot figure it out. Any comments are highly appreciated.
ruby async-await reactor tcpsocket
add a comment |
I need some help in understanding basic 'async/io' example as given here:
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
A reactor pattern (correct please if wrong) is basically kind of scheduler of synchronous tasks, such that upon blocking, a task is suspended and another one is launched, and so on, and in turn tasks are resumed once their operation is unblocked [source]
In the given github example first the echo_server method returning Async::Task
is defined, and assigned to server variable server
Now that the variable is created, the underlying task starts listening on the socket and gets blocked by client.read(512)
call. It is suspended and the flow reaches the loop part where 5 client Async::Task
s one by one write messages to the socket.
And now happens something I don't understand. The server task gets unlocked and replies to the first message. After that it should quit, because there is no kind of loop. However it serves all five requests and quits after that. Obviously there is something I am getting wrong, but I cannot figure it out. Any comments are highly appreciated.
ruby async-await reactor tcpsocket
add a comment |
I need some help in understanding basic 'async/io' example as given here:
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
A reactor pattern (correct please if wrong) is basically kind of scheduler of synchronous tasks, such that upon blocking, a task is suspended and another one is launched, and so on, and in turn tasks are resumed once their operation is unblocked [source]
In the given github example first the echo_server method returning Async::Task
is defined, and assigned to server variable server
Now that the variable is created, the underlying task starts listening on the socket and gets blocked by client.read(512)
call. It is suspended and the flow reaches the loop part where 5 client Async::Task
s one by one write messages to the socket.
And now happens something I don't understand. The server task gets unlocked and replies to the first message. After that it should quit, because there is no kind of loop. However it serves all five requests and quits after that. Obviously there is something I am getting wrong, but I cannot figure it out. Any comments are highly appreciated.
ruby async-await reactor tcpsocket
I need some help in understanding basic 'async/io' example as given here:
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
A reactor pattern (correct please if wrong) is basically kind of scheduler of synchronous tasks, such that upon blocking, a task is suspended and another one is launched, and so on, and in turn tasks are resumed once their operation is unblocked [source]
In the given github example first the echo_server method returning Async::Task
is defined, and assigned to server variable server
Now that the variable is created, the underlying task starts listening on the socket and gets blocked by client.read(512)
call. It is suspended and the flow reaches the loop part where 5 client Async::Task
s one by one write messages to the socket.
And now happens something I don't understand. The server task gets unlocked and replies to the first message. After that it should quit, because there is no kind of loop. However it serves all five requests and quits after that. Obviously there is something I am getting wrong, but I cannot figure it out. Any comments are highly appreciated.
ruby async-await reactor tcpsocket
ruby async-await reactor tcpsocket
edited Jan 3 at 13:03
ioquatix
882922
882922
asked Nov 23 '18 at 11:46
ClergymanClergyman
1461213
1461213
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
echo_client
is executed 5 times as it is invoked from a loop. That function calls endpoint.connect
and sends a single message and reads a single response.
echo_server
is executed 1 time and calls endpoint.accept
which yields the block for each connection. The server reads one message and writes it back.
The server task gets unlocked and replies to the first message. After that it should quit, because there is no kind of loop.
endpoint.accept
is implemented as a loop:
def accept(backlog = Socket::SOMAXCONN, &block)
bind do |server|
server.listen(backlog)
server.accept_each(&block)
end
end
Here is the 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
As you can see, it binds to the socket, listens for incoming connections, and then invokes accept in a loop.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53446123%2fruby-async-io-and-reactor-help-understand-the-example%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
echo_client
is executed 5 times as it is invoked from a loop. That function calls endpoint.connect
and sends a single message and reads a single response.
echo_server
is executed 1 time and calls endpoint.accept
which yields the block for each connection. The server reads one message and writes it back.
The server task gets unlocked and replies to the first message. After that it should quit, because there is no kind of loop.
endpoint.accept
is implemented as a loop:
def accept(backlog = Socket::SOMAXCONN, &block)
bind do |server|
server.listen(backlog)
server.accept_each(&block)
end
end
Here is the 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
As you can see, it binds to the socket, listens for incoming connections, and then invokes accept in a loop.
add a comment |
echo_client
is executed 5 times as it is invoked from a loop. That function calls endpoint.connect
and sends a single message and reads a single response.
echo_server
is executed 1 time and calls endpoint.accept
which yields the block for each connection. The server reads one message and writes it back.
The server task gets unlocked and replies to the first message. After that it should quit, because there is no kind of loop.
endpoint.accept
is implemented as a loop:
def accept(backlog = Socket::SOMAXCONN, &block)
bind do |server|
server.listen(backlog)
server.accept_each(&block)
end
end
Here is the 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
As you can see, it binds to the socket, listens for incoming connections, and then invokes accept in a loop.
add a comment |
echo_client
is executed 5 times as it is invoked from a loop. That function calls endpoint.connect
and sends a single message and reads a single response.
echo_server
is executed 1 time and calls endpoint.accept
which yields the block for each connection. The server reads one message and writes it back.
The server task gets unlocked and replies to the first message. After that it should quit, because there is no kind of loop.
endpoint.accept
is implemented as a loop:
def accept(backlog = Socket::SOMAXCONN, &block)
bind do |server|
server.listen(backlog)
server.accept_each(&block)
end
end
Here is the 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
As you can see, it binds to the socket, listens for incoming connections, and then invokes accept in a loop.
echo_client
is executed 5 times as it is invoked from a loop. That function calls endpoint.connect
and sends a single message and reads a single response.
echo_server
is executed 1 time and calls endpoint.accept
which yields the block for each connection. The server reads one message and writes it back.
The server task gets unlocked and replies to the first message. After that it should quit, because there is no kind of loop.
endpoint.accept
is implemented as a loop:
def accept(backlog = Socket::SOMAXCONN, &block)
bind do |server|
server.listen(backlog)
server.accept_each(&block)
end
end
Here is the 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
As you can see, it binds to the socket, listens for incoming connections, and then invokes accept in a loop.
answered Jan 3 at 9:13
ioquatixioquatix
882922
882922
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53446123%2fruby-async-io-and-reactor-help-understand-the-example%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown