我需要在asyncio循环中获取未来结果,它类似于Calling a coroutine from asyncio.Protocol.data_received
但是PY35和PY34中的asyncio
完全不同,以下是可以在PY34中正确运行的代码,但在PY35中,它将暂停在yield from
并且永不返回。
# 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)
那么,如何在python 3.5中做到这一点?
感谢任何建议。
答案 0 :(得分:1)
你不能从一个不是协程的函数等待协程。 data_received
不是协程,因此正如评论中提到的那样,您需要使用ensure_future
帮助程序来创建"背景"来自你的协程的任务。
不需要开始使用回调:
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))
但是我会指出,asyncio没有提供任何警告,data_received
将使用您期望的完整数据进行调用。通常,您在Protocol
中看到的模式看起来很像这样:
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())
(这只是一个例子,它过多地复制缓冲区,在大多数生产用例中效率非常低)