Python中的多线程MD5校验和

5
我有一个Python脚本,可以递归遍历指定目录,并对找到的每个文件进行校验和。然后它会写入一个日志文件,列出所有文件路径及其MD5校验和。
顺序执行这个脚本需要很长时间,对于每个15MB的50,000个文件而言。然而,我的计算机可用资源比实际使用的资源要多得多。我应该如何调整我的方法,使脚本使用更多资源以更快地执行?
例如,我可以将文件列表分为三部分并为每部分运行一个线程,从而使运行时间缩短3倍吗?
我不太熟悉线程,希望有人能为我的情况提供一个示例。
以下是我顺序执行MD5循环的代码:
for (root, dirs, files) in os.walk(root_path):
    for filename in files:
        file_path = root + "/" + filename
        md5_pairs.append([file_path, md5file(file_path, 128)])

Thanks for your help in advance!


3
最简单的方法是启动您的Python脚本的独立实例,每个实例都被分配一个从root_path开始的子树。 - TJD
3
在尝试任何优化之前,先调查瓶颈所在是一个好主意。例如,如果MD5的时间明显比从磁盘读取文件的时间少很多,那么不要指望能够大幅提升速度。 - SquareRootOfTwentyThree
这是一个很好的观点,我对简单读取和校验进行了基准测试,校验仅增加了大约10%的运行时间。我们的光纤连接SAN的读取速度为8 Gb / s。我认为我可以让这些文件更快地读取,不是吗?读取总计7 GB的600个文件需要88秒钟。 - Jamie
感谢大家的帮助!Stack Overflow 真是太棒了!!! - Jamie
4个回答

5

1
嗨,jsbueno,我尝试使用建议的池,但仅改善了20%的运行时间。这可以更好吗?由于我正在处理大量小文件,将文件列表分成块并将每个块发送到池中是否更好?还是最好将每个单独的md5调用发送到池中? - Jamie
你没有看到超过20%的速度提升可能表明你的处理受到IO限制而不是CPU限制。你应该进行一些分析以确定是否属于这种情况,因为理论上你应该能够在计算部分获得100%的效率。 - Kamil Kisiel
1
如果出现了I/O限制,你可以通过在主进程(或其他进程)中将所有文件读入内存来改善情况。然后每个MD5处理过程就不需要从磁盘加载和进行MD5计算,只需进行MD5计算即可。(当然,前提是你有足够的内存来做这个) - quodlibetor
是的,如果我要在实时案例中检查几TB的数据,可能会用尽内存。不过,我可以尝试分块加载。 - Jamie
结果发现,对于我的情况瓶颈在于IO。实际上,将find命令管道传输到md5命令比在Python中遍历、读取和进行md5快23%。 - Jamie

0
如果你要使用线程,你需要首先初始化你的线程,并让它们从一个Queue.Queue实例中轮询工作。然后在你的主线程中,运行你已经有的for循环,但是不要调用md5file(..),而是将所有参数推送到Queue.Queue上。Python中的线程/队列有一个例子,但也要查看文档:http://docs.python.org/library/queue.html

0

由于全局解释器锁(GIL),线程对于md5.update函数并不会有太大的帮助。您的应用程序永远不会同时执行多个对md5.update函数的调用。我建议您继续尝试优化和改进您的进程池。


1
如果md5file从磁盘读取,那么这就不是真的。在磁盘IO期间,GIL没有被保持。话虽如此,相对于吞吐量问题,线程是解决延迟问题的更好方案... - thebjorn
是的,我想我使用了错误的术语。我认为我想要的是多进程而不是多线程。对吗? - Jamie
1
如果你的程序主要受限于IO,那么多进程并不会有太大的区别,但是_总体而言_,在Python中利用更多的CPU核心的正确方法是使用多进程。 - thebjorn
@thebjorn,但是当计算哈希值时,GIL将被锁定,这可能比IO更昂贵。 - mikerobi
@mikerobi 嗯,通常没有比IO更昂贵的了 - 真的 :-) 根据Jamie(上面)的说法,IO占用了90%的时间。 - thebjorn

0

采用尴尬并行方式,为一批文件启动一个进程。我们在集群上执行此操作。您可以拥有数十个或数百个进程,每个进程都会对几十个文件进行md5处理。此时,磁盘IO将成为瓶颈。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接