为什么asyncio.open_connection(或任何其他协同程序)阻止data_received处理?

Way*_*ner 1 python asynchronous python-asyncio

我从asyncio文档稍微修改了以下代码

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()
Run Code Online (Sandbox Code Playgroud)

但是,当我运行它时,它似乎甚至没有运行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)
Run Code Online (Sandbox Code Playgroud)

但是当我评论出这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
Run Code Online (Sandbox Code Playgroud)

我试过添加:

@asyncio.coroutine
def do_a_thing():
    print("hey, it's a thing!")

def try_stuff():
    print('Trying')
    yield from asyncio.async(do_a_thing())
Run Code Online (Sandbox Code Playgroud)

然后打电话try_stuff来.这会输出"正在建立连接",但不会输出"正在尝试".通过将yield from行更改为简单的调用,输出'Trying'.如果我do_a_thing从那时删除coroutine装饰器我得到输出.

对我来说重要的是我正在尝试创建与第二台服务器的异步连接.但显然,它的存在yield from阻止了任何进一步的处理(至少我可以告诉它 - 它肯定会停止打印).

那么我做错了什么,我该如何解决这个问题呢?

gaw*_*wel 5

yield from 必须在协程中使用.正如我所看到的,data_received因为一些asyncio内部结构而不能成为协同程序.

解决方案是将代码包装在协程中并使用asyncio.Task()调用它.

作为一个例子,你可以看看我的实验