Path: csiph.com!usenet.pasdenom.info!news.redatomik.org!newsfeed.xs4all.nl!newsfeed7.news.xs4all.nl!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.026 X-Spam-Evidence: '*H*': 0.95; '*S*': 0.00; 'val': 0.07; 'abstraction': 0.09; 'foo,': 0.09; 'generators': 0.09; 'loop.': 0.09; 'pause': 0.09; 'throws': 0.09; 'wrong,': 0.09; 'def': 0.13; 'async': 0.16; 'closed")': 0.16; 'coroutines': 0.16; 'foo():': 0.16; 'ignored,': 0.16; 'true:': 0.16; 'wrote:': 0.16; 'string': 0.17; 'example.': 0.18; 'skip:l 30': 0.18; 'try:': 0.18; '2015': 0.20; 'meant': 0.22; 'dropped': 0.22; 'sends': 0.22; 'trying': 0.22; 'bit': 0.23; 'this:': 0.23; 'import': 0.24; 'header:In-Reply-To:1': 0.24; "doesn't": 0.26; 'point.': 0.27; 'message-id:@mail.gmail.com': 0.27; 'yield': 0.27; 'clever': 0.29; 'javier': 0.29; 'loop,': 0.29; 'sleep': 0.29; 'yields': 0.29; 'code': 0.30; 'call.': 0.30; "can't": 0.32; '--------': 0.32; 'done,': 0.33; 'foo': 0.33; 'tue,': 0.34; 'except': 0.34; 'running': 0.34; 'gets': 0.35; 'received:google.com': 0.35; 'next': 0.35; 'something': 0.35; 'but': 0.36; 'list,': 0.36; 'to:addr:python-list': 0.36; 'pm,': 0.36; 'subject:: ': 0.37; 'why': 0.39; 'data': 0.39; 'sure': 0.39; 'to:addr:python.org': 0.40; 'where': 0.40; 'still': 0.40; 'some': 0.40; 'future': 0.60; 'your': 0.60; "you'll": 0.61; 'back': 0.62; 'skip:n 10': 0.62; 'more': 0.63; 'results': 0.66; 'future.': 0.67; 'future,': 0.70; 'design.': 0.72; 'jul': 0.72; '"yield': 0.84; 'confusion.': 0.84; 'flaw': 0.84; 'subject:Send': 0.84; 'to:name:python': 0.84; 'yielded': 0.84; 'suspended': 0.91; 'from.': 0.93; 'tricky': 0.93 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :content-type; bh=gsAmqSgKAo9FephkSgXsRlmKCxfDgUkdUfAUsp32zkE=; b=B9VMOFVBq6o94fHNE2hAovkIA41rn6+Uwqx4gYXxMvgmL0WEPdQ17Puhs2TvVt14c2 Ip3rvuE7ji2gtXYDifo+QOmEZXxvoXFvpX5G7IL4e9R5O6/nSwtfqKqcuuoTqvE/VqIX QE7cxtCIHgdKTFJb+Zw8UmG+zJPxn5wdPf695nXDl4sQvWOPyMVM14KcG0Zxf6sAOHo6 xVtKNZ+gAGDWPG4a5rC6Flqi4bctn0zxhx8jc3X4svmA9sAaUASLSgSpkXAxRMq9kTpk SmDi0SaNmXUOg63JHSTlOCHJJL3X6tbsqydT6kfM4PvjLqWV0JYpEd8hu0RaJH6z7wlw dGcg== X-Received: by 10.50.62.148 with SMTP id y20mr11463084igr.17.1438124823266; Tue, 28 Jul 2015 16:07:03 -0700 (PDT) MIME-Version: 1.0 In-Reply-To: <1195c0a3-05b5-4213-92a7-db005ad7d547@googlegroups.com> References: <97b62bfd-8b6d-45f0-8597-7799ba0ea4af@googlegroups.com> <1195c0a3-05b5-4213-92a7-db005ad7d547@googlegroups.com> From: Ian Kelly Date: Tue, 28 Jul 2015 15:06:23 -0800 Subject: Re: Send data to asyncio coroutine To: Python Content-Type: text/plain; charset=UTF-8 X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.20+ Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 73 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1438124825 news.xs4all.nl 2867 [2001:888:2000:d::a6]:43250 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:94711 On Tue, Jul 28, 2015 at 1:17 PM, Javier 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.