python如何获得BytesIO分配的内存长度?

Posted

技术标签:

【中文标题】python如何获得BytesIO分配的内存长度?【英文标题】:python how to get BytesIO allocated memory length? 【发布时间】:2014-11-09 10:02:27 【问题描述】:

这是我用来测试内存分配的代码

import pycurl
import io


url = "http://www.***.com"
buf = io.BytesIO()


print(len(buf.getvalue()))   #here i am getting 0 as length


c = pycurl.Curl()
c.setopt(c.URL, url)
c.setopt(c.CONNECTTIMEOUT, 10)
c.setopt(c.TIMEOUT, 10)
c.setopt(c.ENCODING, 'gzip')
c.setopt(c.FOLLOWLOCATION, True)
c.setopt(c.IPRESOLVE, c.IPRESOLVE_V4)
c.setopt(c.USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:8.0) Gecko/20100101 Firefox/8.0')
c.setopt(c.WRITEFUNCTION, buf.write)
c.perform()
c.close()

print(len(buf.getvalue()))    #here length of the dowloaded file


print(buf.getvalue())
buf.close()

如何通过 BytesIO 获取分配的缓冲区/内存长度? 我在这里做错了什么? python没有分配固定的缓冲区长度?

【问题讨论】:

显示堆栈跟踪。 为什么不使用像requests这样更体面的客户端库? @WeaselFox 没有错误我只想知道如何获取分配的内存长度 您没有向流中写入任何内容,因此其内容为空。有什么问题?你在说什么内存分配? @interjay python 没有为缓冲区分配固定的内存大小? 【参考方案1】:

我不确定分配的缓冲区/内存长度是什么意思,但是如果您想要存储在 BytesIO 对象中的用户数据的长度,您可以这样做

>>> bio = io.BytesIO()
>>> bio.getbuffer().nbytes
0
>>> bio.write(b'here is some data')
17
>>> bio.getbuffer().nbytes
17

但这似乎等同于您当前使用的len(buf.getvalue())

BytesIO对象的实际大小可以通过sys.getsizeof()找到:

>>> bio = io.BytesIO()
>>> sys.getsizeof(bio)
104

或者你可能很讨厌直接调用__sizeof__()(类似于sys.getsizeof(),但没有适用于对象的垃圾收集器开销):

>>> bio = io.BytesIO()
>>> bio.__sizeof__()
72

BytesIO 的内存根据需要分配,并且确实发生了一些缓冲:

>>> bio = io.BytesIO()
>>> for i in range(20):
...     _=bio.write(b'a')
...     print(bio.getbuffer().nbytes, sys.getsizeof(bio), bio.__sizeof__())
...
1 106 74
2 106 74
3 108 76
4 108 76
5 110 78
6 110 78
7 112 80
8 112 80
9 120 88
10 120 88
11 120 88
12 120 88
13 120 88
14 120 88
15 120 88
16 120 88
17 129 97
18 129 97
19 129 97
20 129 97

【讨论】:

所以你是说内存是根据需要动态分配的? @user4046642:是的,这就是我想要展示的。如果你想要一个固定大小的缓冲区,numpy 中可能有一些你可以使用的东西,例如numpy.empty(50, dtype=numpy.character) len(bio.getbuffer()) 也返回相同的数字【参考方案2】:

io.BytesIO() 返回一个具有函数tell() 的标准文件对象。它报告当前描述符位置并且不复制整个缓冲区以计算总大小为len(bio.getvalue())bio.getbuffer().nbytes。这是获取缓冲区对象中已用内存的确切大小的一种非常快速且简单的方法。

但是,如果您预设了缓冲区,tell() 将指向缓冲区的开头并返回 0,但缓冲区大小不为零。在这种情况下,您可以将指针移动到缓冲区的末尾seek(0,2),这将报告缓冲区的总大小,而无需将整个缓冲区复制到另一块内存中。

我发布并最近更新了示例代码和更详细的答案here

【讨论】:

【参考方案3】:

您还可以使用tracemalloc 获取有关对象大小的间接信息,方法是将内存事件包装在tracemalloc.get_traced_memory()

请注意,您的程序的活动线程(如果有)和副作用会影响输出,但如果采样很多,它也可能更能代表实际内存成本,如下所示。

>>> import tracemalloc
>>> from io import BytesIO
>>> tracemalloc.start()
>>>
>>> memory_traces = []
>>>
>>> with BytesIO() as bytes_fh:
...     # returns (current memory usage, peak memory usage)
        # ..but only since calling .start()
...     memory_traces.append(tracemalloc.get_traced_memory())
...     bytes_fh.write(b'a' * (1024**2))  # create 1MB of 'a'
...     memory_traces.append(tracemalloc.get_traced_memory())
...
1048576
>>> print("used_memory = b".format(memory_traces[1][0] - memory_traces[0][0]))
used_memory = 1048870b
>>> 1048870 - 1024**2  # show small overhead
294  

【讨论】:

以上是关于python如何获得BytesIO分配的内存长度?的主要内容,如果未能解决你的问题,请参考以下文章

python笔记之BytesIO

python 在内存中读写:StringIO / BytesIO

python模块—StringIO and BytesIO

Python之StringIO和BytesIO

Python文件读写StringIO和BytesIO

python学习——StringIO和BytesIO