Re: [Async-sig] Adding asyncio.run() function in Python 3.6
> On Nov 16, 2016, at 3:35 PM, Nathaniel Smith wrote: > > What's the use case for the async generator version? Could the yield be > replaced by 'await loop.shutting_down()’? Async generator version (inspired by contextlib.contextmanager decorator) is needed in cases where you want loop.run_forever. The PR originally proposed to add `asyncio.forever()` (which is the same idea as `loop.shutting_down()`), but nobody particularly liked it. A couple of thoughts/reasons: 1. Some pretty intrusive modifications are required to be made in the event loop to make it work. That means all other event loops (including uvloop) will have to be modified to support it. This is the most important reason. 2. `loop.shutting_down()` is a no go because it’s a method on the loop object. We can discuss `asyncio.shutting_down`. The whole point of this discussion is to get rid of the event loop. 3. `await forever()` and `await shutting_down()` have a naming issue - both look weird: async def main(): srv = await asyncio.start_server(…) try: await asyncio.shutting_down() # or await forever() finally: srv.close() await srv.wait_closed() In the above example, what does the second ‘await’ do? Will it be resolved when the loop is stopped with ‘loop.stop()’? Or when a KeyboardInterrupt occurs? What will happen if you await on it in parallel from 10 different coroutines? It’s just difficult to define a clear semantics of this coroutine. Using an asynchronous generator for this case is easier in terms of implementation and in terms of specifying the execution semantics. And the approach of using generators for such things isn’t new - we have contextlib.contextmanager decorator which is quite popular. Yury ___ Async-sig mailing list Async-sig@python.org https://mail.python.org/mailman/listinfo/async-sig Code of Conduct: https://www.python.org/psf/codeofconduct/
Re: [Async-sig] Adding asyncio.run() function in Python 3.6
What's the use case for the async generator version? Could the yield be replaced by 'await loop.shutting_down()'? On Nov 16, 2016 10:12 AM, "Yury Selivanov" wrote: > One of the remaining problems with the event loop in asyncio is > bootstrapping/finalizing asyncio programs. > > Currently, there are two different scenarios: > > [1] Running a coroutine: > > async def main(): ># your program > loop = asyncio.get_event_loop() > try: > loop.run_until_complete(main()) > finally: > loop.close() > > [2] Running a server: > > loop = asyncio.get_event_loop() > srv = loop.run_until_complete( > loop.create_server(…)) > try: > loop.run_forever() > finally: > try: > srv.close() > loop.run_until_complete(srv.wait_closed()) > finally: > loop.close() > > Both cases are *incomplete*: they don’t do correct finalization of > asynchronous generators. To do that we’ll need to add another 1-3 lines of > code (extra try-finally). > > This manual approach is really painful: > > * It makes bootstrapping asyncio code unnecessarily hard. > > * It makes the documentation hard to follow. And we can’t restructure the > docs to cover the loop only in the advanced section. > > * Most of the people will never know about `loop.shutdown_asyncgen` > coroutine. > > * We don’t have a place to add debug code to let people know that their > asyncio program didn’t clean all resources properly (a lot of unordered > warnings will be spit out instead). > > In https://github.com/python/asyncio/pull/465 I propose to add a new > function to asyncio in Python 3.6: asyncio.run(). > > The function can either accept a coroutine, which solves [1]: > > async def main(): ># your program > asyncio.run(main()) > > Or it can accept an asynchronous generator, which solves [2]: > > async def main(): > srv = await loop.create_server(…)) > try: > yield # let the loop run forever > finally: > srv.close() > await srv.wait_closed() > > asyncio.run(main()) > > asyncio.run() solves the following: > > * An easy way to start an asyncio program that properly takes care of loop > instantiation and finalization. > > * It looks much better in the docs. With asyncio.run people don’t need to > care about the loop at all, most probably will never use it. > > * Easier to experiment with asyncio in REPL. > > * The loop and asynchronous generators will be cleaned up properly. > > * We can add robust debug output to the function, listing the unclosed > tasks, servers, connections, asynchronous generators etc, helping people > with the cleanup logic. > > * Later, if we need to add more cleanup code to asyncio, we will have a > function to add the logic to. > > I feel that we should add this to asyncio. One of the arguments against > that, is that overloading asyncio.run to accept both coroutines and > asynchronous generators makes the API more complex. If that’s really the > case, we can add two functions: asyncio.run(coro) and > asyncio.run_forever(async_generator). > > Also take a look at https://github.com/python/asyncio/pull/465. > > Thanks, > Yury > ___ > Async-sig mailing list > Async-sig@python.org > https://mail.python.org/mailman/listinfo/async-sig > Code of Conduct: https://www.python.org/psf/codeofconduct/ ___ Async-sig mailing list Async-sig@python.org https://mail.python.org/mailman/listinfo/async-sig Code of Conduct: https://www.python.org/psf/codeofconduct/
[Async-sig] Adding asyncio.run() function in Python 3.6
One of the remaining problems with the event loop in asyncio is bootstrapping/finalizing asyncio programs. Currently, there are two different scenarios: [1] Running a coroutine: async def main(): # your program loop = asyncio.get_event_loop() try: loop.run_until_complete(main()) finally: loop.close() [2] Running a server: loop = asyncio.get_event_loop() srv = loop.run_until_complete( loop.create_server(…)) try: loop.run_forever() finally: try: srv.close() loop.run_until_complete(srv.wait_closed()) finally: loop.close() Both cases are *incomplete*: they don’t do correct finalization of asynchronous generators. To do that we’ll need to add another 1-3 lines of code (extra try-finally). This manual approach is really painful: * It makes bootstrapping asyncio code unnecessarily hard. * It makes the documentation hard to follow. And we can’t restructure the docs to cover the loop only in the advanced section. * Most of the people will never know about `loop.shutdown_asyncgen` coroutine. * We don’t have a place to add debug code to let people know that their asyncio program didn’t clean all resources properly (a lot of unordered warnings will be spit out instead). In https://github.com/python/asyncio/pull/465 I propose to add a new function to asyncio in Python 3.6: asyncio.run(). The function can either accept a coroutine, which solves [1]: async def main(): # your program asyncio.run(main()) Or it can accept an asynchronous generator, which solves [2]: async def main(): srv = await loop.create_server(…)) try: yield # let the loop run forever finally: srv.close() await srv.wait_closed() asyncio.run(main()) asyncio.run() solves the following: * An easy way to start an asyncio program that properly takes care of loop instantiation and finalization. * It looks much better in the docs. With asyncio.run people don’t need to care about the loop at all, most probably will never use it. * Easier to experiment with asyncio in REPL. * The loop and asynchronous generators will be cleaned up properly. * We can add robust debug output to the function, listing the unclosed tasks, servers, connections, asynchronous generators etc, helping people with the cleanup logic. * Later, if we need to add more cleanup code to asyncio, we will have a function to add the logic to. I feel that we should add this to asyncio. One of the arguments against that, is that overloading asyncio.run to accept both coroutines and asynchronous generators makes the API more complex. If that’s really the case, we can add two functions: asyncio.run(coro) and asyncio.run_forever(async_generator). Also take a look at https://github.com/python/asyncio/pull/465. Thanks, Yury ___ Async-sig mailing list Async-sig@python.org https://mail.python.org/mailman/listinfo/async-sig Code of Conduct: https://www.python.org/psf/codeofconduct/