import asyncio
asyncio.tasks._DEBUG = True
class EchoServer(asyncio.Protocol):
def connection_made(self, transport):
name = transport.get_extra_info('sockname')
peername = transport.get_extra_info('peername')
print('Connection:',name,'<--',peername)
self.transport = transport
def data_received(self, data):
name = self.transport.get_extra_info('sockname')
peername = self.transport.get_extra_info('peername')
print('Got data:',name,'<--',peername,':',data.decode() )
if name[1] == 8888:
print("Making connection")
reader, writer = yield from asyncio.open_connection('127.0.0.1', 8889, loop=asyncio.get_event_loop())
else:
self.transport.write(data)
self.transport.close()
loop = asyncio.get_event_loop()
coro_1 = loop.create_server(EchoServer, '127.0.0.1', 8888)
coro_2 = loop.create_server(EchoServer, '127.0.0.1', 8889)
server_1 = loop.run_until_complete(coro_1)
server_2 = loop.run_until_complete(coro_2)
print('Serving on {}'.format(server_1.sockets[0].getsockname()))
print('Serving on {}'.format(server_2.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
print("^C caught, exiting")
finally:
server_1.close()
server_2.close()
loop.close()
然而,当我运行它时,它甚至似乎运行 data_received
函数:
Serving on ('127.0.0.1', 8888)
Serving on ('127.0.0.1', 8889)
Connection: ('127.0.0.1', 8888) <-- ('127.0.0.1', 36580)
但是当我注释掉yield from
行时,它会以我期望的方式运行。
Serving on ('127.0.0.1', 8888)
Serving on ('127.0.0.1', 8889)
Connection: ('127.0.0.1', 8888) <-- ('127.0.0.1', 36581)
Got data: ('127.0.0.1', 8888) <-- ('127.0.0.1', 36581) : Hi, gaise!
Making connection
我尝试添加:
@asyncio.coroutine
def do_a_thing():
print("hey, it's a thing!")
def try_stuff():
print('Trying')
yield from asyncio.async(do_a_thing())
并改为调用try_stuff
。这会输出“正在建立连接”,但不会输出“正在尝试”。通过将yield from
行更改为简单的调用,输出'Trying'。如果我从do_a_thing
删除协程装饰器,那么我得到输出。
对我来说重要的是我正在尝试创建与第二台服务器的异步连接。但显然,yield from
的存在阻止了任何进一步的处理(至少我可以告诉它 - 它肯定会因打印而停止)。
那么我做错了什么,我该如何解决这个问题呢?
答案 0 :(得分:5)
yield from
必须才能在协程中使用。正如我所看到的,data_received因为一些asyncio内部结构而不能成为协同程序。
解决方案是将代码包装在协程中并使用asyncio.Task()调用它。
作为示例,您可以查看我的experiments
答案 1 :(得分:3)
正如gawel所提到的,yield from
必须在协程中使用,尽管Server类在某些asyncio调用中,但这些函数并不是神奇的协同程序。
EchoServer
需要看起来像这样:
class EchoServer(asyncio.Protocol):
def connection_made(self, transport):
name = transport.get_extra_info('sockname')
peername = transport.get_extra_info('peername')
print('Connection:',name,'<--',peername)
self.transport = transport
# This is where the magic happens
@asyncio.coroutine
def send_data(self, data):
print("Making connection")
reader, writer = yield from asyncio.open_connection('127.0.0.1', 8889)
print("Connection made")
writer.write(data)
print("Data sent")
# For some reason, not providing n caused this to not return anything
resp = yield from reader.read(1024)
print("Got response")
self.transport.write(resp)
print('Data returned:',resp)
def data_received(self, data):
name = self.transport.get_extra_info('sockname')
peername = self.transport.get_extra_info('peername')
print('Got data:',name,'<--',peername,':',data.decode() )
if name[1] == 8888:
print("making task")
asyncio.Task(self.send_data(data))
print("done making task")
else:
print("Sending response")
self.transport.write(data[::-1])