The _step() function in Task registers a callback that gets called when the
Future completes. This callback calls _step() again to move the coroutine
forward. (Note there are two separate Futures involved here -- the Task (a
Future subclass) which wraps the coroutine, and the Future that the
coroutine is actually waiting for.) Ultimately there is always a Task
wrapping a coroutine representing the "main" code -- unless you have a pure
server, in which case whenever a connection comes in, a task wrapping a
coroutine is probably created (unless you do everything with callbacks at
the Protocol level -- but it's much more convenient to use coroutines.
Check out connection_made() in streams.py for example.


On Thu, Feb 20, 2014 at 5:26 PM, Nikolaus Rath <[email protected]> wrote:

> Guido van Rossum <[email protected]> writes:
> >> Suppose somebody is using asyncio, and we're in the middle of some
> >> asyncio coroutine:
> >>
> >> @asyncio.coroutine
> >> def do_stuff(b)
> >>     #...
> >>     yield from asyncio.sleep(1)
> >>     # ...
> >>     yield from other_fn()
> >>     # ...
> >>
> >> Is there something that I could yield in other_fn that will cause it to
> >> be resumed once a specific fd is writable?
> >>
> >
> > If other_fn() was a regular function it could return a Future. Or if it
> was
> > an asyncio coroutine (decorated with @asyncio.coroutine) it could yield
> > from a Future. However it can't just yield a Future -- that will make a
> > boobietrap go off specifically set up to prevent you from making the
> > mistake of yielding a Future instead of yielding *from* it.
> >
> > Then of course you have to arrange for the Future's result to be set when
> > your FD is ready. You do that with an I/O callback. I'll explain below.
> >
> >
> >> I'm thinking about something like this:
> >>
> >> def other_fn():
> >>     # ...
> >>     yield asyncio.resume_me_when_writable(some_fd)
> >>     buf = os.write(some_fd, 42)
> >>     # ...
> >>
> >> The add_writer() method of the BaseEventLoop seems related to this, but
> >> doesn't quite do what I want. I don't want to register a callback, I
> >> want to resume the coroutine..
> >>
> >
> > Yes, you do want to register a write callback that calls
> f.set_result(None)
> > (and the probably removes the write callback.
> >
> > I think if you study the implementation of sock_sendall() (and
> > _sock_sendall()) in asyncio/selector_events.py you'll get my gist;
> > sock_sendall() is a function returning a Future that will be made
> complete
> > when the I/O is done; _sock_sendall() first just tries to send (all FDs
> > here are nonblocking) and if that fails it registers itself as a write
> > callback and then upon being called again it unregisters itself and tries
> > to send again (hoping that this time it will not block, otherwise it'll
> > just re-register itself and so on).
>
>
> Ah, I think I have an idea what to do, thanks!
>
>
> There is one more thing I'm struggling to understand though: if my
> callback gets called and marks the future as done, how does the main
> event loop know that it can call next() on the future now? Looking at
> futures.py, set_result() doesn't seem to do anything than update the
> internal state and call any registered callbacks. Is the event-loop
> registering callback for itself when it receives a future?
>
> Thanks,
> Nikolaus
>
> --
> Encrypted emails preferred.
> PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6  02CF A9AD B7F8 AE4E 425C
>
>              »Time flies like an arrow, fruit flies like a Banana.«
>



-- 
--Guido van Rossum (python.org/~guido)

Reply via email to