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)
