什么时候应该使用BytesIO.getvalue()而不是.getbuffer()



根据BytesIO文档:

getbuffer((

返回缓冲区内容的可读写视图,而不复制它们。此外,更改视图将透明地更新缓冲区的内容:

getvalue((

返回包含缓冲区全部内容的字节。

所以getbuffer似乎更复杂。但是,如果您不需要可写视图?那么你会简单地使用getvalue吗?权衡是什么?

最小示例

在这个例子中,他们似乎做了完全相同的事情:

# Create an example
from io import BytesIO
bytesio_object = BytesIO(b"Hello World!")
# Write the stuff
with open("output.txt", "wb") as f:
f.write(bytesio_object.getbuffer())

这个问题很老了,但似乎没有人充分回答这个问题。

简单地说:

  • obj.getbuffer()创建一个memoryview对象
  • 每次写入时,或者如果存在memoryviewobj.getvalue()都需要创建一个新的完整值
  • 如果您还没有编写并且没有memoryview,那么obj.getvalue()是最快的访问方法,并且不需要副本

情况就是这样:

  • 创建另一个io.BytesIO时,请使用obj.getvalue()
  • 对于随机存取读写,确定使用obj.getbuffer()
  • 避免频繁插入读写。如果必须,则确定使用obj.getbuffer(),除非您的文件很小
  • 避免在放置缓冲区时使用obj.getvalue()

在这里,我们可以看到,如果没有缓冲区,一切都很快,也很好:


# time getvalue()
>>> i = io.BytesIO(b'f' * 1_000_000)
>>> %timeit i.getvalue()
34.6 ns ± 0.178 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
# time getbuffer()
>>> %timeit i.getbuffer()
118 ns ± 0.495 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
# time getbuffer() and getvalue() together
>>> %timeit i.getbuffer(); i.getvalue()
173 ns ± 0.829 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

一切都很好,一切都如你所愿。但让我们看看当有一个缓冲区时会发生什么:

>>> x = i.getbuffer()
>>> %timeit i.getvalue()
33 µs ± 675 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

请注意,我们不再以纳秒进行测量,而是以微秒为单位进行测量。如果你del x,我们又快了。这一切都是因为当memoryview存在时,Python必须考虑到BytesIO被写入的可能性。因此,为了给用户一个确定的状态,它复制了缓冲区。

使用getbuffer((更好,因为如果您有非常大的数据,复制它们可能需要很长时间。和(来自PEP 20(:

显式优于隐式
但值未定义-它可能是str或字节。缓冲区总是字节

相关内容

  • 没有找到相关文章

最新更新