【问题标题】:In Trio, how do you write data to a socket without waiting?在 Trio 中,如何在不等待的情况下将数据写入套接字?
【发布时间】:2020-09-08 19:41:15
【问题描述】:

在 Trio 中,如果您想将一些数据写入 TCP 套接字,那么显而易见的选择是send_all

my_stream = await trio.open_tcp_stream("localhost", 1234)
await my_stream.send_all(b"some data")

请注意,这两者都通过套接字发送该数据并且等待它被写入。但是如果你只是想将要发送的数据排队,而不是等待它被写入(至少,你不想在同一个协程中等待)?

在 asyncio 中这很简单,因为这两个部分是独立的函数:write()drain()。例如:

writer.write(data)
await writer.drain()

当然,如果您只想写入数据而不是等待它,您可以直接调用write() 而无需等待drain()。 Trio 中是否有等效的功能?我知道这种双功能设计是有争议的,因为it makes it hard to properly apply backpressure,但在我的应用程序中我需要将它们分开。

现在我已经通过为每个连接创建一个专用的编写器协程并拥有一个内存通道来将数据发送到该协程来解决这个问题,但是与在调用一个或两个函数之间进行选择相比,这是相当多的麻烦,并且这似乎有点浪费(大概在引擎盖下还有一个发送缓冲区,而我的内存通道就像那个缓冲区顶部的缓冲区)。

【问题讨论】:

    标签: asynchronous tcp python-trio


    【解决方案1】:

    我在 Trio 聊天和 Nathaniel J. Smith,Trio 的创建者 replied with this 上发布了这个:

    Trio 不会在“幕后”维护缓冲区,不。这里只有内核的发送缓冲区,但不管你是否愿意,内核都会施加背压,所以这对你没有帮助。

    使用后台写入任务 + 无限内存通道基本上是 asyncio 为您隐式做的事情。

    另一个选项,如果您将一条消息分成多个部分,然后想在完成后发送它,则将它们附加到一个字节数组中,然后在最后调用一次 send_all,在同一个地方你会在 asyncio 中调用 drain

    (但显然,只有在每条逻辑消息之后都调用 drain 时才有效;如果你只是调用 write 并让 asyncio 在后台将其耗尽,那么这无济于事)

    所以这个问题是基于一个误解:我想写入 Trio 的隐藏发送缓冲区,但不存在这样的东西!使用等待流并调用send_all() 的单独协程比我想象的更有意义。

    我最终使用了这两种想法的混合体(使用带有内存通道的单独协程与使用字节数组):将数据保存到字节数组,然后使用 条件变量 ParkingLot 发出信号到另一个可以编写的协程。这让我可以合并写入,还可以手动检查缓冲区是否变得太大。

    【讨论】:

    • 这可能是最好的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-15
    • 2020-11-01
    • 1970-01-01
    • 2019-06-19
    • 1970-01-01
    • 1970-01-01
    • 2013-08-27
    相关资源
    最近更新 更多