El miércoles, 29 de julio de 2015, 1:07:22 (UTC+2), Ian escribió: > On Tue, Jul 28, 2015 at 1:17 PM, Javier <jcarm...@gmail.com> wrote: > > Hello again. I have been investigating a bit your example. I don't > > understand why I can't write something like this: > > > > -------- > > > > import asyncio > > > > def foo(): > > print("start foo") > > try: > > while True: > > val = yield > > print("foo:", val) > > yield from asyncio.sleep(3) > > except GeneratorExit: > > print("foo closed") > > print("exit foo") > > > > def bar(next): > > print("start bar") > > next.send(None) > > try: > > while True: > > val = yield > > next.send("bar/"+val) > > except GeneratorExit: > > print("bar closed") > > print("exit bar") > > > > def fun(next): > > next.send(None) > > for e in ["hello", "world", "I'm", "pythonist"]: > > next.send(e) > > > > @asyncio.coroutine > > def run(): > > fun(bar(foo())) > > > > loop = asyncio.get_event_loop() > > loop.run_until_complete(run()) > > loop.close() > > Because "yield from asyncio.sleep(3)" doesn't magically pause the > coroutine as you want it to. It yields a future, which is meant to be > yielded back up the coroutine chain to the event loop. The event loop > would then resume the coroutine once the future is done, which in the > case of asyncio.sleep will happen after the sleep timer completes. > > In your example, the future never makes it back to the event loop. > asyncio.sleep yields the future to foo, and since foo is suspended by > a yield from, foo yields the future to bar, where it is the result of > the next.send call. The return value of next.send is ignored, so the > future just gets dropped on the floor at this point. bar yields to > fun, which sends bar the next string in its list, "world". bar sends > "world" to foo, and since foo is still suspended by a yield from, it > sends "world" on to the asyncio.sleep future. Not a new asyncio.sleep > future, but the same one that it's still yielding from. The future > then realizes that something is wrong, because its generator code is > running again but it doesn't have a result yet, so it throws that > AssertionError. > > If you want the yield from in foo to work properly, then you need to > make sure that the future gets back to the event loop, and if you do > that in some tricky way other than a yield from chain, you'll also > need to make sure that you're not trying to send it more data before > foo has resumed. > > > I think this is a big flaw in python/asyncio design. > > I don't entirely disagree. I think that the implementation of async > coroutines on top of synchronous coroutines on top of generators is > overly clever and results in a somewhat leaky abstraction and a fair > amount of confusion.
I see, so I was wrong. I used to see event loop, and yield from as a language improvement but it's actually a library improvement that, as a side effect, prevents you from usign some language features like ordinary generator/coroutine communication. That is a pity. Thank you very much for your time and explanations, now I understand some points. I'll keep on learning asyncio. -- https://mail.python.org/mailman/listinfo/python-list