在 asyncio.Protocol.data_received() 中调用协程并获得未来?
Calling coroutine and getting future in asyncio.Protocol.data_received()?
我需要在 asyncio 循环中获取未来的结果,它类似于
但是 PY35 和 PY34 中的 asyncio
完全不同,这里是可以在 PY34 中正确 运行 的代码,但在 PY35 中它会在 yield from
处暂停并且永远不会 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)
那么,如何在 python 3.5 中做到这一点?
如有任何建议,我们将不胜感激。
您不能等待来自非协程的函数的协程。 data_received
不是协程,因此正如评论中提到的,您需要使用 ensure_future
帮助器从协程创建一个 "background" 任务。
但是不需要开始使用回调:
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())
(这只是一个示例,它复制缓冲区的方式过多,在大多数生产用例中效率非常低)
我需要在 asyncio 循环中获取未来的结果,它类似于
但是 PY35 和 PY34 中的 asyncio
完全不同,这里是可以在 PY34 中正确 运行 的代码,但在 PY35 中它会在 yield from
处暂停并且永远不会 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)
那么,如何在 python 3.5 中做到这一点?
如有任何建议,我们将不胜感激。
您不能等待来自非协程的函数的协程。 data_received
不是协程,因此正如评论中提到的,您需要使用 ensure_future
帮助器从协程创建一个 "background" 任务。
但是不需要开始使用回调:
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())
(这只是一个示例,它复制缓冲区的方式过多,在大多数生产用例中效率非常低)