Python 3.x Python异步io流
我在asyncio文档中查看了以下代码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(
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。