Send data to asyncio coroutine

Javier jcarmena at gmail.com
Wed Jul 29 00:41:05 CEST 2015


El martes, 28 de julio de 2015, 23:18:11 (UTC+2), Javier  escribió:
> El martes, 21 de julio de 2015, 15:42:47 (UTC+2), Ian  escribió:
> > On Tue, Jul 21, 2015 at 5:31 AM,  <jcarmena at gmail.com> wrote:
> > > Hello, I'm trying to understand and link asyncio with ordinary coroutines. Now I just want to understand how to do this on asyncio:
> > >
> > >
> > > def foo():
> > >     data = yield 8
> > >     print(data)
> > >     yield "bye"
> > >
> > > def bar():
> > >     f = foo()
> > >     n = f.next()
> > >     print(n)
> > >     message = f.send("hello")
> > >     print(message)
> > >
> > >
> > > What is the equivalent for coro.send("some data") in asyncio?
> > 
> > I don't know of any reason why you couldn't do it just like the above.
> > However, the exchange would not be asynchronous, if that is your goal.
> > 
> > > coro.send on an asyncio coroutine throws AssertionError: yield from wasn't used with future.
> > 
> > So somehow a future got involved where it shouldn't have been. What
> > was the actual code that you tried to run?
> > 
> > Note that while "yield" and "yield from" look similar, they are quite
> > different, and you cannot send to a generator that is currently paused
> > at a "yield from".
> > 
> > If you want to emulate bidirectional communication similar to
> > coro.send asynchronously, I think you'll need to use Futures to
> > mediate, something like this (lightly tested):
> > 
> > @asyncio.coroutine
> > def foo(fut):
> >     data, fut = yield from send_to_future(8, fut)
> >     print("foo", data)
> >     fut.set_result("bye")
> > 
> > @asyncio.coroutine
> > def bar():
> >     n, fut = yield from start_coro(foo)
> >     print("bar", n)
> >     message = yield from send_to_future("hello", fut)
> >     print("bar", message)
> > 
> > def start_coro(coro):
> >     future = asyncio.Future()
> >     asyncio.async(coro(future))
> >     return future
> > 
> > def send_to_future(data, future):
> >     new_future = asyncio.Future()
> >     future.set_result((data, new_future))
> >     return new_future
> 
> 
> 
> 
> 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()
> 
> -------
> 
> The expected output is:
> 
> start bar
> start foo
> foo: bar/hello
> foo: bar/world
> foo: bar/I'm
> foo: bar/phytonist
> bar closed
> exit bar
> foo closed
> exit foo
> 
> But the yield from asyncio.sleep(3) call raises AssertionError, however it's inside a Task!
> I think this is a big flaw in python/asyncio design.


I think that force the developer to 'yield from' all function calls to keep async capabilities is a big mistake, it should be more flexible, like this:

import asyncio

@asyncio.coroutine
fun non_blocking_io():
    """ Everybody knows I'm doing non blocking IO """
    ...

fun foo():
    """ I invoke functions that do IO stuff """
    data = yield from non_blocking_io()
    yield from store_data_db(data)
    ...

fun bar():
    """ I don't know what foo implementation does """
    foo()

asyncio.async(bar())


Does python 3.5 await/async solve this?


More information about the Python-list mailing list