Python 3.x 如何加速下面的python3代码?

Python 3.x 如何加速下面的python3代码?,python-3.x,Python 3.x,所以我试图解析一个巨大的文件,下面的代码解析起来太长了。文件大小为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), en

所以我试图解析一个巨大的文件,下面的代码解析起来太长了。文件大小为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 "
请注意,由引号包装的文件中的字符串不应拆分,必须作为一个整体进行解析(仍然包装在引号中)


罪魁祸首显然是shlex.split()。这是一个相当昂贵的操作(为每个拆分创建一个全新的对象,其中包含大量的样板文件),因此如果您的数据遵循所提供的格式,您可以尝试手动解析数据

因此,这里有一个方法,它对示例数据的执行方式与
shlex.split()
相同:

因此,速度要快12倍多。但我们可以做得更好。。。这种方法的问题在于,它在Python端有大量缓慢的
str.find()
调用(尽管逐字执行会更慢)和字符串洗牌,因此快速的C端没有机会发挥其魔力。如果您要在C中实现这一点(进行一些优化)并将其作为一个模块加载,速度会非常快,但遗憾的是

因此,我认为,
regex
可能会更快,因为它主要在C端执行,即使您给它更复杂的规则,它也应该能够在足够大的数据上优于纯Python字符串搜索和操作。因此,下一位候选人:

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
是的,regex one几乎比shlex.split()快24倍。!它们都会为您的测试数据生成相同的分割结果

但是在您跳入和跳出
shlex
之前,您需要彻底测试这两种类型,以确保它们适合您的数据-例如,它们无法识别转义引号或特殊的POSIX拆引号字符串,因此,如果您的数据中存在此类情况,您必须将其考虑在内

此外,如果您想提高一点点速度,请立即写入输出,而不是存储在一个集合中,以便稍后循环:

with open(os.path.join(out_dir, 'extractedLinks.txt'), 'a+', encoding="utf8") as out_file:
    links = set()  # temp store to ensure uniqueness...
    for current_file in file_list:
        with open(os.path.join(in_dir, current_file), encoding="utf8") as in_file:
            for line in in_file:
                try:
                    link = shlex.split(line)[2]  # or whatever other function
                    if link not in links:
                        links.add(link)
                        out_file.write(link + "\n")
                except Exception:
                    continue

假设你将在你庞大的输入文件中收集数百万行,这可能会缩短一两秒钟…

如果你打算否决我的问题,请解释你为什么这么做。谢谢。你能不能把你要解析的文件的10行写进去,这样我就可以给你写一个快速的熊猫解析器?是的,我现在就做@MattI已经把它添加到了帖子中@Matt谢谢你的帮助。除了在拆分时忽略带引号的字符串之外,还有其他要求吗?回答得好,我本来打算投一个熊猫版的,但你的基准测试似乎否定了这个需求哇:哦,真是让人大吃一惊。谢谢你提供这么多细节。我从你的回答中学到了很多。
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
with open(os.path.join(out_dir, 'extractedLinks.txt'), 'a+', encoding="utf8") as out_file:
    links = set()  # temp store to ensure uniqueness...
    for current_file in file_list:
        with open(os.path.join(in_dir, current_file), encoding="utf8") as in_file:
            for line in in_file:
                try:
                    link = shlex.split(line)[2]  # or whatever other function
                    if link not in links:
                        links.add(link)
                        out_file.write(link + "\n")
                except Exception:
                    continue