Python 字符串处理优化

Python string processing optimization

所以最近我一直在制作一个 python 脚本,用于从大型文本文件 ( > 1 GB ) 中提取数据。问题基本上归结为从文件中选择文本行,并在其中搜索某个数组中的字符串(该数组中可以包含多达 1000 个字符串)。这里的问题是我必须找到该字符串的特定出现,并且该字符串可能会在该文件中出现无限次。此外,还需要一些解码和编码,这会额外减慢脚本速度。 代码看起来像这样:

strings = [a for a in open('file.txt')]

with open("er.txt", "r") as f:
    for chunk in f:
        for s in strings
            #do search, trimming, stripping ..

我的问题是: 有没有办法优化这个?我尝试了多处理,但它帮助不大(或者至少是我实现它的方式)这里的问题是这些块操作不是独立的并且 strings 列表可能会在其中一个过程中被改变。 任何优化都会有所帮助(字符串搜索算法、文件读取等)我在循环中断方面做了尽可能多的工作,但它仍然运行得很慢。

考虑调用外部进程(grep 等)来加快处理速度并减少必须在 Python 内处理的数据量。

另一种方法是使用编译后的正则表达式过滤或预过滤数据,因为这样您的内部循环就会使用标准库的优化代码。

你也可以尝试 Cython 或类似的热内循环,参见例如https://books.google.de/books?id=QSsOBQAAQBAJ&dq=high+perf+python&hl=en 了解详情。

如果你能准确知道字符串是如何以二进制(ASCII、UTF-8)编码的,你就可以mmap整个文件一次存入内存;它的行为与 file.read() 获得的大 bytearray/bytes(或 Python 2 中的 str)完全一样;那么这样的 mmap 对象将可以通过 str 正则表达式 (Python 2) 或 bytes 正则表达式 (Python 3).

mmap 是许多操作系统上最快的解决方案,因为只读映射意味着 OS 可以在页面准备就绪时自由映射;不需要交换 space,因为数据由文件支持。 OS 还可以直接映射缓冲区缓存中的数据,零复制 - 因此比裸读多赢。

示例:

import mmap
import re

pattern = re.compile(b'the ultimate answer is ([0-9]+)')
with open("datafile.txt", "rb") as f:
    # memory-map the file, size 0 means whole file
    mm = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ)

    # PROT_READ only on *nix as the file is not writable
    for match in pattern.finditer(mm):
        # process match
        print("The answer is {}".format(match.group(1).decode('utf8')))

    mm.close()

现在,如果 datafile.txt 包含文本:

the ultimate answer is 42

在 1 GB 数据的某个地方,这个程序将是最快的 python 解决方案之一:

The answer is 42

请注意 pattern.finditer 也接受 startend 参数,可用于限制尝试匹配的范围。


ivan_pozdeev 所述,这需要 1 GB 的可用虚拟地址 space 来映射一个 GB 的文件(但不一定是 1 GB 的 RAM),这在 32-位进程,但在 64 位操作系统和 CPU 上几乎可以肯定地假定为 "no-problem"。在 32 位进程上,该方法仍然有效,但您需要将大文件映射为较小的块 - 因此现在操作系统和处理器的位非常重要。