Python 3.x Python异步io流

Python 3.x Python异步io流,python-3.x,sockets,tcp,async-await,python-asyncio,Python 3.x,Sockets,Tcp,Async Await,Python Asyncio,我在asyncio文档中查看了以下代码 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(

我在asyncio文档中查看了以下代码

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操作,所以写方法也应该等待,对吗

然而,我现在能够理解为什么reader.read是可以等待的,而writer.write不是?因为它们都是I/O操作,所以写方法也应该等待,对吗

不一定。和之间的基本不对称是
read()
必须返回实际数据,而
write()
的操作纯粹是由于副作用。因此,
read()
必须等待,因为当数据还不可用时,它需要挂起调用的协同路由。另一方面,
write()

这种设计具有重要的后果,例如写入数据的速度比另一方读取数据的速度快,这会导致缓冲区无限膨胀,并且
write()
期间的异常实际上会丢失。这两个问题都可以通过调用应用反压力来解决,即将缓冲区写入操作系统,必要时在进程中暂停协程。这样做直到缓冲区大小下降到某个值以下。
write()
文档建议“调用
write()
后应加上
drain()


write()
中缺少背压是在基于回调的层上实现异步IO流的结果,在该层中,非异步
write()
比完全异步的替代方法更便于使用。有关该主题的详细说明,请参见的作者的这篇文章。

注意:Python 3.8将有
awrite()
aclose()
异步流方法,以避免
write()
/
drain()
close()
混淆。@AndrewSvetlov这太棒了!有一个
flush()
coroutine也是非常有用的,它是
file.flush
的异步等价物。其想法是简单地将流缓冲区刷新到操作系统,就像drain()一样,但没有水印。我怀疑
flush()
是否有用,因为刷新没有分布式系统的交付保证。对等方仍然无法接收刷新的数据。文件系统则不同:刷新的缓冲区位于内核内存中,如果不重新启动,它们将保存在磁盘上(不太可能)
fsync
提供了更强大的保证。无论如何,如果您仍然想要
flush()
——请在bugs.python.org上为discussion@AndrewSvetlov的确,
flush()
不提供交付保证,但将数据传输到操作系统仍然很有用。这与刷新常规文件相同,其中数据不同步,而是传递到内核。socket还有一个内核缓冲区,Nathaniel对此进行了讨论,他继续认为asyncio在内核缓冲区之上的水印系统是多余的,会导致缓冲区膨胀。(我搜索了async sig归档文件,但找不到对该声明的反驳。)但由于
flush()
drain()
正交,我将只提交一个BPO问题。我曾在aiohttp服务器中禁用水印。结果,我得到了10-15%的减速IIRC。