• python读取大文件md5校验性能优化比较


    with open(filename, "rb") as f:
    
    • 1
    1. f.read() 读取整个文件,通常将文件内容放到一个字符串变量中;
    2. f.readline() 次读取一行内容;
    3. f.readlines() 一次性读取所有内容并按行返回list;
      当读取的文件较大时,全部读取内存中,会导致内存溢出

    第一种:readline()

    def md5_sum(filename):
        with open(filename, "rb") as f:
            f.seek(0)
            line = f.readline()
    
            md5 = hashlib.md5()
            md5.update(line)
    
            while line:
                line = f.readline()
                md5.update(line)
    
            f_md5 = md5.hexdigest()
        print(f_md5)
        return f_md5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    我以一个1.4G的文件进行测试

    4dcafe2e69d6d0a8979cb4eb7c26c3fd
    耗时:  6.345685958862305
    Current memory usage is 0.008476MB; Peak was 5.260233MB
    
    • 1
    • 2
    • 3

    耗时 6s,峰值内存占用5.2M

    第二种:readlines()

    def md5_sum2(filename):
        with open(filename, "rb") as f:
            f.seek(0)
            md5 = hashlib.md5()
    
            for line in f.readlines():
                md5.update(line)
    
            f_md5 = md5.hexdigest()
        print(f_md5)
        return f_md5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    一次性将文件读到内存中,如果内存不够会报错

    4dcafe2e69d6d0a8979cb4eb7c26c3fd
    耗时:  7.258216857910156
    Current memory usage is 0.008476MB; Peak was 1654.899472MB
    
    • 1
    • 2
    • 3

    耗时 7.2s,峰值内存占用1654M
    反而速度更慢!

    第三种:read()

    def md5_sum3(filename):
        def chunked_file_reader(file, block_size=1024 * 16):
            """生成器函数:分块读取文件内容,使用 iter 函数
            """
            # 首先使用 partial(fp.read, block_size) 构造一个新的无需参数的函数
            # 循环将不断返回 fp.read(block_size) 调用结果,直到其为 '' 时终止
            for chunk in iter(partial(file.read, block_size), b''):
                yield chunk
    
        with open(filename, "rb") as f:
            f.seek(0)
            md5 = hashlib.md5()
    
            for line in chunked_file_reader(f):
                md5.update(line)
    
        f_md5 = md5.hexdigest()
        print(f_md5)
        return f_md5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    利用read block_size读取大小限制,构造生成器

    4dcafe2e69d6d0a8979cb4eb7c26c3fd
    耗时:  3.0910959243774414
    Current memory usage is 0.014733MB; Peak was 0.053139MB
    
    • 1
    • 2
    • 3

    耗时 3,峰值内存占用0.05M

    第四种:read() + itertools

    def md5_sum4(filename):
        buffer = 1024 * 1024
    
        with open(filename, "rb") as f:
            buf_gen = takewhile(lambda x: x, (f.read(buffer) for _ in repeat(None)))
            md5 = hashlib.md5()
    
            for line in buf_gen:
                md5.update(line)
        f_md5 = md5.hexdigest()
        print(f_md5)
        return f_md5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    itertools 有更好的for loop 性能
    这里切片大小设置为 1024*1024

    4dcafe2e69d6d0a8979cb4eb7c26c3fd
    耗时:  2.7328171730041504
    Current memory usage is 0.00074MB; Peak was 2.103334MB
    
    • 1
    • 2
    • 3

    耗时 2.7s,峰值内存占用2.1M

    总结

    1. 后端分片的话可以考虑多线程,多进程的处理方案
    2. 但是一般业务场景 更多是前端上传的文件流的形式
    3. 更好的方案是前端拆分大文件,后端在接受文件的同时算出md5
  • 相关阅读:
    HDFS 底层交互原理,看这篇就够了!
    计算机视觉 CV 八股分享 [自用](更新中......)
    堆栈的类型及特点
    Springboot 基于微信小程序的高校学生疫情在校封闭管理系统的设计与实现 毕业设计-附源码240904
    Qt6,使用 UI 界面完成命令执行自动化的设计
    C# —— 方法的参数列表
    抗住大批量请求的高并发架构设计经验
    STL简介
    【分布式能源的选址与定容】基于非支配排序多目标粒子群优化算法求解分布式能源的选址与定容附Matlab代码
    最「难搞」的英伟达也开源了,下一个会是谁?
  • 原文地址:https://blog.csdn.net/u011342224/article/details/127548685