如何使用asyncio/aiohttp确定最佳缓冲区大小

3
在使用Python中的asyncio时,如何确定read()的最佳参数?是12个字节?还是100个字节?
async with self._session.get(url, headers=headers) as response:
    chunk_size = 12
    result = ''

    while True:
       chunk = await response.content.read(chunk_size)
          if not chunk:
              break
          elif isinstance(chunk, (bytes, bytearray)):
              data = chunk.decode('utf8')
               result += data
1个回答

6
当使用Python中的asyncio时,如何决定read()的最佳参数?12字节?100字节?
您可以安全地选择比此更大的数字。如果数字太小(例如仅为1),则您的循环将由许多对StreamReader.read的调用组成,每个调用都会带有固定的开销 - 它必须检查缓冲区中是否有内容,然后返回其中一部分并更新剩余的缓冲区,或者等待新内容到达。另一方面,如果请求的大小过大,则在理论上可能需要不必要的大型分配。但是,由于StreamReader.read允许返回少于指定数据量的数据,因此它永远不会返回大于内部缓冲区(默认情况下为64 KiB)的块,因此这不是一个问题。 总之:任何大于1024的数字都可以,因为它足够大,避免了不必要的函数调用。请求超过65536在大多数情况下与请求65536相同。当我不关心绝对最佳性能时(调试时更小的块更容易看),我倾向于请求1024字节,而在需要时请求更大的值,如16384。顺便说一句,这些数字不必是2的幂,这只是从更低级别的语言惯例而来。

在处理aiohttp流时,您可以调用readany,这是一个方法,它只返回可用的任何数据,如果没有可用的数据,则等待一些数据到达并返回该数据。如果您处理aiohttp流,那么这可能是最好的选择,因为它只会从内部缓冲区中提供数据,而无需担心其大小。


1
非常有帮助的答案!我在asyncio/streams.py中检查了缓冲区限制,您介意更新您的答案:_DEFAULT_LIMIT = 2 ** 16 # 64 KiB - v1z3
此外,您是否认为从同一进程中的缓冲区中的read(2**16)或readany()足够快以在单个协程中运行(将其拆分成较小的块没有实际好处)? - v1z3
@v1z3 很好的发现,我已经更正了默认缓冲区大小值。我不确定你所说的“足够快以在单个协程中运行”的意思是什么 - 就像你不能通过从多个协程中读取相同的流来加速它一样。 - user4815162342
在大多数代码中,我认为人为地创建比实际从网络接收到的更小的块没有好处。如果代码由于某些特定领域的原因需要更小的块,则从asyncio开始请求这些块肯定是有意义且更有效率的。但是这种代码在我看来相当罕见,典型的代码要么不关心块的大小(例如你问题中的代码),要么对块有更具体的要求(例如以换行符或EOF结尾,由readline()提供)。 - user4815162342
谢谢!我进行了一些基准测试并回答了自己的猜想性问题。 - v1z3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接