• 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
  • 相关阅读:
    TinyGrad
    C++ unique_ptr
    INnoDB(索引与算法)
    Python进阶:上下文管理器
    《从0开始写一个微内核操作系统》0-环境准备
    Clion~Clion常用配置和插件
    【工具】转码silk格式为mp3
    【Java开发工具】下载安装eclipse并汉化配置教程(所以操作系统通用)
    聚焦数据库和新兴硬件的技术合力 中科驭数受邀分享基于DPU的数据库异构加速方案
    404. 左叶子之和
  • 原文地址:https://blog.csdn.net/u011342224/article/details/127548685