代码之家  ›  专栏  ›  技术社区  ›  Zach Gates

从溪流中提取的正确方法是什么?

  •  24
  • Zach Gates  · 技术社区  · 9 年前

    我有一个 Connection asyncio

    class Connection(object):
    
        def __init__(self, stream_in, stream_out):
            self._streams_ = (stream_in, stream_out)
    
        def read(self, n_bytes: int = -1):
            stream = self._streams_[0]
            return stream.read(n_bytes)
    
        def write(self, bytes_: bytes):
            stream = self._streams_[1]
            stream.write(bytes_)
            yield from stream.drain()
    

    new_connection 将创建新的 对象,并期望接收4个字节。

    @asyncio.coroutine
    def new_connection(stream_in, stream_out):
        conn = Connection(stream_in, stream_out)
        data = yield from conn.read(4)
        print(data)
    

    客户端发送4个字节。

    @asyncio.coroutine
    def client(loop):
        ...
        conn = Connection(stream_in, stream_out)
        yield from conn.write(b'test')
    

    yield from 每次打电话给 read write . 我试着移动 进入 因此。

    def read(self, n_bytes: int = -1):
        stream = self._streams_[0]
        data = yield from stream.read(n_bytes)
        return data
    

    但是,我得到的不是预期的数据字节,而是生成器对象。

    <generator object StreamReader.read at 0x1109983b8>
    

    阅读 收益来自 . 我的目标是减少 新建_连接

    @asyncio.coroutine
    def new_connection(stream_in, stream_out):
        conn = Connection(stream_in, stream_out)
        print(conn.read(4))
    
    2 回复  |  直到 4 年前
        1
  •  5
  •   user2508324 user2508324    9 年前

    StreamReader.read is a coroutine ,您唯一的调用选项是a)将其包装在 Task Future 并通过事件循环运行,b) await 从定义为 async def ,或c)使用 yield from @asyncio.coroutine

    自从 Connection.read new_connection ),您不能重用该事件循环来运行 将来 对于 StreamReader。阅读 : event loops can't be started while they're already running stop the event loop (灾难性的,可能不可能正确执行)或 create a new event loop (凌乱且违背了使用协同程序的目的)。这两者都不可取,所以 联系阅读 需要是一个协同程序或 async

    其他两个选项( 等候 异步定义 协同程序或 收益来自 @异步。协同程序 -装饰功能)大多是等效的。唯一的区别是 async def and await were added in Python 3.5 收益来自 @异步。协同程序 是唯一的选择(协作和 asyncio 在3.4之前不存在,因此其他版本无关紧要)。就我个人而言,我更喜欢使用 异步定义 等候 异步定义 比装饰师更干净、更清晰。

    简而言之:有 联系阅读 成为协同程序(使用decorator或 异步 等候 )调用其他协同程序时( await conn.read(4) 在里面 新建_连接 await self.__in.read(n_bytes) 联系阅读 ).

        2
  •  2
  •   RageCage    9 年前

    StreamReader source code 第620行实际上是函数用法的完美示例。

    self.__in.read(n_bytes) 不仅仅是一个合作项目(考虑到它是从 asyncio 模块XD),但它会在线生成结果。所以它实际上是一个发电机,你需要从中获得收益。

    def read(self, n_bytes : int = -1):
        data = bytearray() #or whatever object you are looking for
        while 1:
            block = yield from self.__in.read(n_bytes)
            if not block:
                break
            data += block
        return data
    

    赛尔夫__在里面读取(n_字节) 如果是生成器,则必须继续从中生成,直到生成一个空结果,以表示读取结束。现在,read函数应该返回数据,而不是生成器。你不必屈服于这个版本的 conn.read()