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列表可能在其中一个中被改变.任何优化都会有所帮助(字符串搜索算法,文件读取等)我尽可能多地做了关于循环中断的事情,但它仍然运行得很慢.
如果您可以确切地知道字符串是如何以二进制(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还接受可用于限制尝试匹配范围的参数start和end参数.
正如ivan_pozdeev所指出的,这需要1千兆字节的空闲虚拟地址空间来映射一个千兆字节的文件(但不一定是1千兆字节的RAM),这在32位进程中可能很难,但几乎可以肯定是"无问题" "在64位操作系统和CPU上.在32位进程上,该方法仍然有效,但您需要以较小的块映射大文件 - 因此现在操作系统和处理器的位真正重要.