使用mmap与popen

2 投票
2 回答
1380 浏览
提问于 2025-04-16 20:28

我需要快速读取和处理大约40MB的gzipped文本文件,并且希望尽量减少输入输出的开销(因为这些文件还被其他人使用)。到目前为止,我找到的最快的方法是这样的:

def gziplines(fname): 
    f = Popen(['zcat', fname], stdout=PIPE)
    for line in f.stdout:
        yield line

然后:

for line in gziplines(filename)
    dostuff(line)

但我想尝试的(如果这样更快的话)是这样的:

def gzipmmap(fname): 
    f = Popen(['zcat', fname], stdout=PIPE)
    m = mmap.mmap(f.stdout.fileno(), 0, access=mmap.ACCESS_READ)
    return m

可惜的是,当我尝试这样做时,我遇到了这个错误:

>>> m = mmap.mmap(f.stdout.fileno(), 0, access=mmap.ACCESS_READ)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
mmap.error: [Errno 19] No such device

尽管当我尝试:

>>> f.stdout.fileno()
4

所以,我觉得我对这里发生的事情有些基本的误解。 :(

我有两个问题:

1) 使用这个mmap方法是否能更快地将整个文件加载到内存中进行处理?

2) 我该如何实现这个?

非常感谢大家……这里的每个人都已经提供了非常大的帮助!

~Nik

2 个回答

1

管道是不能使用内存映射的。

case MAP_PRIVATE:
      ...
if (!file->f_op || !file->f_op->mmap)
        return -ENODEV;

而且管道的文件操作里没有 mmap 这个功能。

4

来自 mmap(2) 的手册页面:

   ENODEV The  underlying  file system of the specified file does not sup-
          port memory mapping.

你不能对流进行内存映射,只能对真正的文件或者匿名的交换空间进行操作。你需要自己把流中的内容读到内存里。

撰写回答