所以我试图解析一个巨大的文件,下面的代码需要很长时间才能解析。文件大小为2GB。我希望有些人可以帮助我加快速度。
import os, shlex
def extractLinkField(inDir, outDir):
fileList = os.listdir(inDir)
links = set()
for File in fileList:
print(File)
with open(os.path.join(inDir, File), encoding="utf8") as inFile:
for line in inFile:
try:
links.add(shlex.split(line)[2])
except Exception:
continue
outFile = open(os.path.join(outDir, 'extractedLinks.txt'), 'a+', encoding="utf8")
for link in list(links):
outFile.write(link + '\n')
outFile.close()
Path = os.path.join(os.getcwd(), 'logs')
extractLinkField(Path, os.getcwd())
文件格式如下:
90 "m z pd gk y xr vo" "n l v ogtc dj wzb" "d zi pfgyo b tmhek" "df qu venr ls hzw j"
82 "p wgd lv f kt eb uq" " ij cw v a r y qp" " pf qdlcgm jz os y" "f xm n cr ublzig"
89 "c pgib a ost whk" "ria m h fvcb es z" "qzoy g xbr makc" "ms lqc v ektb w "
66 "zxm pe hb vi dj " "rg ebfwp y zv oakm" "b nut ko je m crsh" " imsxtzfw g ka j l "
2 "uyhnpt l dj qak " "o hned j pqub t a " "v hlyc afwi sgr p" "h wtvi g o nc sujqx"
17 "apo ufliz qctbd xh " "k lxgbrcwzf mnhtq p" "z gk m rsbu l" " ds m au w cior "
9 " h t ac jpn ok mz" "aty rs w box vk zefp" "nm fbc x egt zruap " "xg oi j z wyf v dqp"
82 "xs q ve k oi c " " z lfa dwiprxb ku g" "kua p f b oqz jrt " " t wlvy d po qrx e"
51 "cx iq wuvhb gkmo y" " u p yx bv mjz r" "oatc wuxd yfgjs ri " "vbg w h ife myl"
91 "cdqkp rn u ow h f" "ko rt y c eis d q jl" " lv fe r zpju yw " " wz vtxa jn lg s"
83 "bts dl kjycre ozv " " k i q m r ypsu lh " "pr exw sznqa yvu i " " uq tzk nomrx e "
请注意,引号包含的文件中的字符串不应拆分,必须整体解析(仍包含在引号中)
答案 0 :(得分:2)
显然,罪魁祸首是shlex.split()
。这是一个相当昂贵的操作(为每个拆分创建一个包含大量样板的全新对象),因此如果您的数据遵循所呈现的格式,您可以尝试手动解析数据。
所以,这是一种方法,对{1}}的样本数据采用相同的方法:
shlex.split()
与def manual_split(data):
data = data.strip() # clear artifacts
tokens = []
head = 0
open_quote = False
while True:
if open_quote:
quote = data.find('"', head)
if quote == -1: # this should not happen, no matching quotes
break
tokens.append(data[head:quote])
head = quote + 1
open_quote = False
else:
space = data.find(' ', head)
quote = data.find('"', head)
if space == -1 and quote == -1: # nothing more to split
break
if space < quote:
if not tokens or space - head > 1:
tokens.append(data[head:space])
head = space + 1
open_quote = False
else:
open_quote = True
head = quote + 1
if head < len(data): # add leftovers, if any, as the last token
tokens.append(data[head:])
return tokens
相比,在这里运行相同的样本数据(包括循环)有时候适合您:
shlex.split()
因此,速度提高了12倍以上。但是我们可以做得更好......这种方法的问题在于它有很多慢shlex.split: 10,000 loops: 11.51 s, per loop: 1.151 ms
manual_split: 10,000 loops: 0.951 s, per loop: 95.11 µs
次调用(尽管逐个字符会更慢)和Python端的字符串改组,因此快速的C端不会没有机会发挥它的魔力。如果你要在C中实现它(通过一些优化)并将其作为一个模块加载它会非常快,但是唉......
所以,我认为str.find()
可能会更快地执行它,因为它主要在事物的C端执行,即使你给它更复杂的规则,它应该能够胜过纯Python字符串搜索&amp;操纵足够大的数据。那么,下一个候选人:
regex
现在我们有了最终的基准:
import re
FIELDS_PATTERN = re.compile(r"(?:\"(.*?)\"|(\S+))")
def regex_split(data):
return [x[0] or x[1] for x in FIELDS_PATTERN.findall(data)]
是的,正则表达式几乎比shlex.split: 10,000 loops: 11.51 s, per loop: 1.151 ms
manual_split: 10,000 loops: 0.951 s, per loop: 95.11 µs
regex_split: 10,000 loops: 0.482 s, per loop: 48.16 µs
快24倍!它们都会为您的测试数据生成相同的拆分结果。
shlex.split()
之前但是,你需要彻底测试这两者以确保它们适合你的数据 - 例如,他们不会识别转义报价或特殊的POSIX解开引用字符串,因此如果您的数据中存在此类情况,则必须将其考虑在内。
另外,无关,如果你想加一点点加速,立即写入你的输出,而不是存储在一个集合中,以便以后循环它:
shlex
假设您将在您的巨大输入文件中收集数百万行,这可能会减少一两秒......