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

17
根据 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())

1
从 cpython 代码 https://github.com/python/cpython/blob/master/Modules/_io/bytesio.c 中可以看出,当调用 getvalue 时,如果已经分配了额外的缓冲空间,则会重新调整内容缓冲区并剥离多余的缓冲空间。而 getbuffer 则会返回缓冲区本身,以便在需要时进行修改。 - Kris
1
@Kris,“getvalue”似乎比“getbuffer”更快。如果每次都要复制,那么它怎么可能更快呢?此外,与“getbuffer”不同,“getvalue”始终指向相同的基础对象。 - NicoAdrian
2个回答

2
这个问题很老了,但是似乎没有人给出足够的答案。
简单来说:
- `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已经被写入的可能性。因此,为了给用户一个明确的状态,它会复制缓冲区。


1
使用getbuffer()更好,因为如果你有非常大的数据,复制它们可能需要很长时间。而且(来自PEP 20):
明确优于隐式。

“getvalue”似乎比“getbuffer”更快。如果每次都要复制,那么它怎么可能更快呢?此外,与“getbuffer”不同,“getvalue”始终指向相同的基础对象。 - NicoAdrian

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