Python字符串处理优化

deg*_*ion 2 python string file-io

最近我一直在制作一个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 ..
Run Code Online (Sandbox Code Playgroud)

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

Ant*_*ala 5

如果您可以确切地知道字符串是如何以二进制(ASCII,UTF-8)编码的,那么您可以mmap整个文件一次存入内存; 它会表现得像是一个大的bytearray/bytes(或str在Python 2中)得到的file.read() ; 那么这样的mmap对象可以通过str正则表达式(Python 2)或bytes正则表达式(Python 3)进行搜索.

mmap是许多操作系统上最快的解决方案,因为只读映射意味着操作系统可以在页面准备好后自由映射; 不需要交换空间,因为数据由文件支持.操作系统还可以直接映射缓冲区缓存中的数据,无需复制 - 因此在裸读时实现双赢.

例:

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('ascii')))

    mm.close()
Run Code Online (Sandbox Code Playgroud)

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

the ultimate answer is 42
Run Code Online (Sandbox Code Playgroud)

在1千兆字节的数据中,该程序将成为最快的python解决方案之一:

The answer is 42
Run Code Online (Sandbox Code Playgroud)

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


正如ivan_pozdeev所指出的,这需要1千兆字节的空闲虚拟地址空间来映射一个千兆字节的文件(但不一定是1千兆字节的RAM),这在32位进程中可能很难,但几乎可以肯定是"无问题" "在64位操作系统和CPU上.在32位进程上,该方法仍然有效,但您需要以较小的块映射大文件 - 因此现在操作系统和处理器的位真正重要.