我正在查看异步文档中的以下代码。
import asyncio
async def tcp_echo_client(message):
reader, writer = await asyncio.open_connection(
'127.0.0.1', 8888)
print(f'Send: {message!r}')
writer.write(message.encode())
data = await reader.read(100)
print(f'Received: {data.decode()!r}')
print('Close the connection')
writer.close()
await writer.wait_closed()
asyncio.run(tcp_echo_client('Hello World!'))
但是我现在能够理解为什么可以等待reader.read而不是writer.write了?由于它们都是I / O操作,因此写方法还应该等待吗?
答案 0 :(得分:3)
但是我现在能够理解为什么可以等待reader.read而不是writer.write了?因为它们都是I / O操作,所以写方法也应该是可以等待的吧?
不一定。 read()
和write()
之间的基本不对称性是LazyMapSequence
必须返回实际数据,而read()
纯粹是出于副作用。因此write()
必须是可以等待的,因为当数据尚不可用时,它需要暂停调用协程。另一方面,read()
可以(通过异步方式)通过将数据存储在某个缓冲区中并安排将其写入适当的时间来实现。
此设计具有重要的后果,例如,写入数据的速度快于另一面的读取速度,这会导致缓冲区无限制地膨胀,并且write()
期间的异常会被有效地丢失。这两个问题都可以通过调用writer.drain()
来解决,该threshold应用 backpressure ,即将缓冲区写出到OS,必要时将协程挂起。直到缓冲区大小降到article以下为止。 write()
文档建议“对write()
的呼叫后应跟write()
。”
drain()
中缺乏背压是由于在基于回调的层之上实现了异步流,其中非异步write()
比完全异步使用起来更加方便替代。请参见Nathaniel J Smith的作者trio的{{3}},以获取对该主题的详细处理。