Python中的read()和write()如何处理大块数据/内存管理

4

我正在编写一些Python代码,用于在各个点拼接大型文件。我曾经在C中做过类似的事情,我分配了一个1MB的字符数组,并将其用作读/写缓冲区。这非常简单:将1MB读入字符数组,然后将其写出。

但是在Python中,我认为它是不同的,每次调用size = 1M的read()函数,它都会分配一个1M长的字符字符串。希望当缓冲区超出范围时,它将在下一次垃圾回收通行证中被释放。

Python会以这种方式处理分配吗?如果是这样,那么常数分配/释放循环是否会计算机昂贵?

我能告诉Python像在C中那样使用相同的内存块吗?还是Python虚拟机足够智能以自行处理?

我想我最终的目标实际上有点像在Python中实现dd。


7
你正在担心一些无关紧要的事情。输入输出是慢的,分配器是快的。在尝试优化并让代码更加复杂之前,请先进行性能分析。 - Dietrich Epp
1个回答

10

在docs.python.org网站中搜索readinto,以查找适合您使用的Python版本的文档。readinto是一种低级功能,它们看起来很像这样:

readinto(b) 将最多len(b)个字节读入bytearray b中,并返回读取的字节数。

与read()类似,除非底层原始流处于交互模式之外,否则可以向其发出多个读取请求。

如果底层原始流处于非阻塞模式,并且此时没有可用数据,则会引发BlockingIOError。

但不要过早担心它。 Python以惊人的速度分配和释放动态内存,反复获取并释放一个微不足道的兆字节的成本可能会被淹没在噪音中。请注意,CPython主要是基于引用计数的,因此当缓冲区超出范围时,它将立即被回收。至于Python是否每次重用相同的内存空间,机会很大,但不能保证。 Python不会尝试强制执行这一点,但根据整个分配/释放模式和系统C的细节malloc()/free()实现的情况,不可能重用;-)


1
谢谢,readinfo() 正是我想要的。出于好奇,我决定使用 1MB 缓冲区比较 readinfo()read() 在一个 300MB 文件上的表现。结果发现,readinfo()read() 快了约 40%。因此,也许重新分配缓冲区的成本并不那么微不足道。 - rhlee
有趣! 我得记住那个;-) 很高兴它能帮到你。 - Tim Peters
@rhlee:你确定在测试期间文件没有被操作系统缓存到内存中吗? - Chronial
@Chronial:我认为这里涉及到了缓存,因为在第一次读取文件后,事情加速了很多。所以我舍弃了前几次的时间,并使用接下来的五次左右的平均值,这是相当一致的。 - rhlee
所以你确保有内存缓存参与了吗?那么你的测量似乎就毫无意义了,因为这是关于IO的,而IO是很慢的,所以分配并不重要。你测量的是内存中的复制,而在那里分配当然是很重要的。 - Chronial

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