Calling coroutine and getting future in asyncio.Protocol.data

I need to get the future result inside asyncio loop, it is similar to Calling a coroutine from asyncio.Protocol.data_received

But asyncio in PY35 and PY34 are completely different, here are the code which could run correctly in PY34, but in PY35 it will pause at yield from and never return.

# PY34
class RelayClient(asyncio.Protocol):
    pass

class Server(asyncio.Protocol):
    def data_received(self, data):
        # I need to connect to another address, and get future result at current function.
        # Also I could not run loop.run_until_complete().
        loop = asyncio.get_event_loop()
        result = yield from loop.create_connection(RelayClient, 'www.google.com', 443)
        do_some_thing_with_result(result)

So, how to do this in python 3.5?

Any advice is appreciated.


You cannot await a coroutine from a function that is not a coroutine. data_received is not a coroutine, so as was mentioned in the comments, you need to use the ensure_future helper to create a "background" task from your coroutine.

No need to start using callbacks however:

async def do_stuff(data):
        result = await loop.create_connection(RelayClient, 'www.google.com', 443)
       await do_some_thing_with_result(result)

class Server(asyncio.Protocol):
    def data_received(self, data):
        asyncio.ensure_future(do_stuff(data))

I would point out however, that asyncio gives no garanties whatsoever that data_received will be called with the complete data you are expecting. Usually the pattern you see in a Protocol looks a lot like this:

async def process_line(line):
    ...

class Server(asyncio.Protocol):
    def __init__(self):
        self.buffer = b''

    def data_received(self, data):
        self.buffer += data

        if b'n' not in self.buffer:
            return

        line, self.buffer = self.buffer.split(b'n')
        fut = asyncio.ensure_future(process_line(line))
        fut.add_done_callback(self._handle_exception)

    def _handle_exception(self, fut):
        if fut.exception() is not None:
            print('Processing failed', fut.exception())

(this is just an example, it copies the buffer way too much and would be very inefficient in most production use-cases)

链接地址: http://www.djcxy.com/p/53232.html

上一篇: asyncio如何暂停协程直到发送被调用

下一篇: 调用协程并在asyncio.Protocol.data中获得未来