Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python中迭代大文件的最有效方法(10GB+;)_Python_File_Design Patterns_Matching - Fatal编程技术网

Python中迭代大文件的最有效方法(10GB+;)

Python中迭代大文件的最有效方法(10GB+;),python,file,design-patterns,matching,Python,File,Design Patterns,Matching,我正在编写一个Python脚本来遍历两个文件——一个包含UUID列表,另一个包含大量日志条目——每行包含另一个文件中的一个UUID。该程序的目的是从文件1创建一个UUID列表,然后每次在日志文件中找到UUID时,在每次找到匹配项时增加相关值 长话短说,计算每个UUID在日志文件中出现的次数。 目前,我有一个列表,其中UUID作为键填充,“hits”作为值填充。然后是另一个循环,循环遍历日志文件的每一行,并检查日志中的UUID是否与UUID列表中的UUID匹配。如果匹配,则递增该值 for

我正在编写一个Python脚本来遍历两个文件——一个包含UUID列表,另一个包含大量日志条目——每行包含另一个文件中的一个UUID。该程序的目的是从文件1创建一个UUID列表,然后每次在日志文件中找到UUID时,在每次找到匹配项时增加相关值

长话短说,计算每个UUID在日志文件中出现的次数。 目前,我有一个列表,其中UUID作为键填充,“hits”作为值填充。然后是另一个循环,循环遍历日志文件的每一行,并检查日志中的UUID是否与UUID列表中的UUID匹配。如果匹配,则递增该值

    for i, logLine in enumerate(logHandle):         #start matching UUID entries in log file to UUID from rulebase
        if logFunc.progress(lineCount, logSize):    #check progress
            print logFunc.progress(lineCount, logSize)  #print progress in 10% intervals
        for uid in uidHits:
            if logLine.count(uid) == 1:             #for each UUID, check the current line of the log for a match in the UUID list
                uidHits[uid] += 1                   #if matched, increment the relevant value in the uidHits list
                break                                #as we've already found the match, don't process the rest
        lineCount += 1               
它可以正常工作,但我相信有一种更有效的方法来处理文件。我阅读了一些指南,发现使用“count”比使用编译的正则表达式要快。我认为分块而不是逐行读取文件可以减少磁盘I/O时间,从而提高性能,但测试文件~200MB的性能差异是可以忽略的。如果有人有其他方法,我将非常感激:)

从功能上思考

  • 编写一个函数,它将获取日志文件的一行并返回uuid。比如说,把它称为uuid

  • 将此函数应用于日志文件的每一行。如果您使用的是Python 3,则可以使用内置函数映射;否则,您需要使用itertools.imap

  • 将此迭代器传递给collections.Counter

    collections.Counter(map(uuid, open("log.txt")))
    
  • 这将是非常有效的

    有几点意见:

    • 这将完全忽略UUID列表,只计算日志文件中出现的UUID。如果您不想这样做,您需要对程序进行一些修改

      • 因为使用了错误的数据结构,所以代码速度很慢。你在这里想要的就是口述

      • 你试过了吗?它是分布式计算框架的Python实现。我不确定您是否会获得性能提升,因为在使用10GB数据之前,我还没有处理过它,尽管您可能会探索这个框架。

        这不是对您的问题的5行回答,但PyCon'08提供了一个名为。还有一个后续教程叫做


        生成器教程特别以大日志文件处理为例。

        正如上面的人所说,使用10GB文件,您可能会很快达到磁盘的极限。对于纯代码的改进,生成器建议非常有用。在Python2.x中,它看起来像

        uuid_generator = (line.split(SPLIT_CHAR)[UUID_FIELD] for line in file)
        
        听起来这实际上不一定是python的问题。如果您没有做任何比计算uuid更复杂的事情,那么Unix可能比python更快地解决您的问题

        cut -d${SPLIT_CHAR} -f${UUID_FIELD} log_file.txt | sort | uniq -c 
        

        尝试使用探查器测量大部分时间花在哪里

        优化的最佳位置取决于数据的性质:例如,如果UUID列表不是很长,您可能会发现很大一部分时间花在“If logFunc.progress(lineCount,logSize)”上。如果列表很长,则可以将
        uidHits.keys()
        的结果保存到循环外的变量中,并迭代该变量,而不是字典本身,但是Rosh Oxymoron建议首先查找id,然后在uidHits中检查它,这可能会更有用


        在任何情况下,都可以消除
        lineCount
        变量,改用
        i
        。和
        find(uid)!=-如果行很长,1
        可能比count(uid)==1要好。

        文件I/O通常被缓冲,而不管您实际读取的块大小。是否需要更高效?需要多长时间?你需要多长时间?您可能已经达到了存储(磁盘)的性能极限,在这种情况下,无论Python脚本的速度有多快都无关紧要。它现在正在运行一个测试文件—它正在运行10GB文件的一半,大约需要30分钟。作为我第一次出游Python,我真的不知道这是快还是慢。无需在x分钟内完成,但更快更好;)在您的示例中,第二条if语句为空(之后没有缩进代码)。你能修好吗?你要检查文件中每一行的所有UID。相反,在每一行中找到UUID并在字典中查找。在代码中最常被调用的部分尽量少做。感谢您的输入-一旦这个测试运行完成,我得到了我的资源,我会看一看。我想我在dict上使用了一个列表,因为我想维护uuid的顺序,但我想我以后可以使用该列表作为索引,然后从dict中提取相应的值?@SG84您可能会看到一篇关于Python生成器的优秀文章,特别是关于处理大文件的文章。你会得到启发:-)我之前确实试过一个发电机,在我把大脑从地板上拿起来并让它工作后,性能提升与在文件上使用for循环没有太大区别。不过,感谢链接,这一切都有助于更好地阅读,因此在了解生成器和集合模块的诀窍之后,我修改了代码中的两个函数,250MB文件的总执行时间从96.4秒减少到5.4秒!!这是一场巨大的胜利。非常感谢大家的投入:)