根据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
对象- 每次写入时,或者如果存在
memoryview
,obj.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或字节。缓冲区总是字节