Pardon my misreading...
Darin McBride
darin.mcbride at shaw.ca
Tue Jan 1 23:26:53 CET 2013
On Tuesday January 1 2013 10:36:46 AM Michael Alan Dorman wrote:
> Darin, Marc, I appreciate your responses.
>
> I fear I did a poor job of explaining my concern---using 'synchronous'
> in my description and 'sleep' in my example obscured my intent.
>
> I was surprised to find that while a single call to AE::postpone does
> not block the event loop from running, multiple consecutive calls to
> AE::postpone will block the event loop from running until they all
> complete, and recursive calls further contribute to this.
Ah, I see the code, yes, that makes sense. Except for the part where you're
doing recursive postponed calls ;)
That is, I don't think it would be normal, and thus not particularly
interesting, that you'd call postpone recursively. Instead, I would expect
that whatever is in the postponed part is either going to run quickly, or
going to create some more events with callbacks to be called during the event
loop.
So, as an example of that:
use AnyEvent;
my $loop = AE::cv;
my $tick; $tick = AE::timer 0, 0.75, sub {
print "tick\n";
};
my $postponements = 5;
my $postponement; $postponement = sub {
if ($postponements--) {
my $p = $postponements;
print "iter $p\n";
AE::postpone {
print "postpone: $p\n";
my $t; $t = AE::timer 1, 0, sub {
undef $t;
$postponement->();
};
};
print "done $p\n";
} else {
undef $tick;
$loop->send();
}
};
$postponement->();
$loop->recv;
__END__
Here I'm using AE::postpone and AE::timer.
I suspect that implementing promises in Coro might make for less "strange"
promise-using code, and that doing it with straight AE might mean some
documentation on this, but, in practice, I don't think this will be much of a
real issue, other than in your .t files.
For example, using the SYNOPSIS as on github, the "then" method would call
AE::postpone when each fetch completed, if I'm reading this right, which is
possibly all in a single loop of the event loop, but unlikely. And, if it is,
they will all be handled at the end of the current loop, and then you move on.
I don't see why these should be called recursively.
> Re-reading the documentation, I see a glimmer of recognition of this
> behavior, but I think users would be better served by a straightforward
> statement that the *only* guarantee is that the current function will
> not be in the call-stack by the time your code is executed, and if you
> want to be certain the event loop will fire, you should use the
> "AE::timer 0, 0" idiom.
>
> Incidentally, as a user, I find this difference in behavior makes it
> useless to me---I will simply use the "AE::timer 0, 0" idiom
> instead---and I fear it could lead to unexpected latency in end-user
> code if a library writer makes use of it.
Sorry, I'm missing the distinction. AE::postpone simply is a deferral to the
end of the *current* loop, and if you're in one postpone, you're already at
the end of the loop, so it'll run the next one immediately in the current
loop.
Note that you can implement a similar postpone function that works the way you
want (I think) easily enough. Run everything postponed prior to the call to
postpone, but anything postponed during the postpone will run at the end of
the *next* loop cycle. Untested, but I'm thinking:
our $MIKE_PP_W;
our @MIKE_PP;
sub _Mike_PP {
undef $MIKE_PP_W;
my @pp = @MIKE_PP;
@MIKE_PP = ();
&{ shift @pp } while @pp;
}
sub Mike_PP(&) {
push @MIKE_PP, shift;
$MIKE_PP_W ||= AE::timer 0, 0, \&_Mike_PP;
()
}
But I don't think this saves much over using AE::timer 0, 0, sub {...}
directly.
And, as I said, I'm not sure of a non-.t use case that this is an issue for.
Or maybe I still don't really understand the issue.
More information about the anyevent
mailing list