【问题标题】:Why does asyncio.open_connection (or any other coroutine) prevent data_received from processing?为什么 asyncio.open_connection (或任何其他协程)会阻止 data_received 处理?
【发布时间】:2014-02-12 12:16:11
【问题描述】:

我将以下代码从asyncio documentation略微修改

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 行更改为一个简单的调用确实会输出“正在尝试”。如果我从do_a_thing 中删除协程装饰器,那么我会得到输出。

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

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

【问题讨论】:

    标签: python asynchronous python-asyncio


    【解决方案1】:

    yield from 必须在协程中使用。如我所见, data_received 不能是协程,因为有一些 asyncio 内部结构。

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

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

    【讨论】:

    • 看来你是对的,通过创建另一个方法并将其包装在 @asyncio.coroutine 方法中,我能够得到预期的结果。
    【解决方案2】:

    正如 gawel 提到的,yield from 必须在协程中使用,尽管 Server 类在一些异步调用中,但这些函数并不是神奇的协程。

    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])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-16
      • 1970-01-01
      • 2013-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-21
      • 1970-01-01
      相关资源
      最近更新 更多