Okay, so... blocking/non-blocking 101 (sortakinda):
When an operation is "blocking" what it literally means is that the
operation blocks further execution of the program. For example opening a
socket with Socket is a blocking operation, since the actual connection
attempt blocks until a result is available. This also applies to files
and reading data from them.
Non-blocking is a method where you can keep up executing the program; an
"old" method of doing this is to use the select() system call. What
happens is that instead of reading data from a socket until you run out
is that you use select() to find out which file descriptors are "ready"
for reading or writing, if a fd is ready for reading you can then read
data from it.
Of course there are better methods available these days, but those are
implementation details. The thing you have to understand is that
non-blocking requires a little bit of thought beforehand. There is no
"magic sauce" that will suddenly make code non-blocking.
Yes, morbo and hypnotoad are non-blocking because they have been
designed to be; courtesy of Mojo::IOLoop, which is an event loop
(well... in "big picture" terms). An event loop basically boils down to:
while(1) {
do_some_timer_stuff;
check_any_fds_for_readability;
handle_readable_fds;
check_any_fds_for_writabiliy;
handle_writable_fds;
}
So, you do still need to actually inform the event loop that it needs to
check for something. Now Mojo::IOLoop does let you do this on plain
"Socket" connections, but you'd have to get the file descriptor, then
use Mojo::IOLoop's functionality to get it to be taken up into the checks.
That's why Mojo::IOLoop->client works out of the box, because it does
that part already, for you.
The other key part is that any event loop will be using callbacks -
because you obviously don't want to be looping through a bunch of if
blocks to see if somethings' readable, Mojo::IOLoop already does that
for you, so when things are in fact readable, it will trigger a callback
- and inside the callback you can handle whatever you need to be doing.
But... you can in fact block inside an event loop. This is considered to
be one of the pitfalls, because blocking inside the event loop will
pretty much halt the entire event loop for the duration of the blocking
taking place; that's why any time you are considering doing anything
non-blocking, you need to make sure the entire code path leading in,
through, and out of it is also non-blocking, otherwise you're not
getting any benefits out of it at all, and in fact are probably causing
a hell of a lot of issues at that point.
Silly example time; imagine you want to write a little proxy that just
grabs a single page. And it's a huge page, like, 5Mb of data; so in your
controller you do this:
sub sillyhugedataproxy {
my $self = shift;
if(my $tx = $self->ua->get('http://www.superhugepage.com/blah.html')) {
if(my $res = $tx->success) {
$self->render(text => $res->body);
} else {
$self->render(text => 'error');
}
}
}
That will not be non-blocking - mostly because Mojo::UserAgent is built
do allow both styles and if you never pass it a callback it will assume
you want to block. The above example also is the typical way of doing it
with LWP (except you substitute the self->ua->get bit for the
appropriate LWP incantations).
Now try this on for size:
sub sillyhugedataproxy {
my $self = shift;
$self->render_later;
$self->ua->get('http://www.superhugepage.com/blah.html' => sub {
my ($ua, $tx) = (@_);
if(my $res = $tx->success) {
$self->render(text => $res->body);
} else {
$self->render(text => 'error');
}
});
}
That is non-blocking. The sub will be exited before the the result has
been completely fetched, but thanks to 'render_later' Mojolicious knows
it can expect a response to be rendered at some later point in time; the
callback passed to ua->get is called once all data has been read and the
request parsed, the reading of said data is done in a non-blocking
fashion (if you want the details, see the code ;)) - and that's where
you then render your response.
The above pattern is what you'd use to talk to a backend API over HTTP.
You can also do this for MongoDB as long as you use the Mango driver
(because sri made it and it's also designed to support non-blocking out
of the box); for other things such as ZMQ or RabbitMQ you will have to
find a module that implements the appropriate protocol *and* does things
in a non-blocking fashion; for example AnyEvent::RabbitMQ can do it for
RabbitMQ.
Anyway, writing out stuff like this at 5am in the morning isn't going to
make it super clear but it's the best I can do :P
--
You received this message because you are subscribed to the Google Groups
"Mojolicious" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/mojolicious.
For more options, visit https://groups.google.com/groups/opt_out.