• 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
  • 相关阅读:
    Java泛型中通配符的使用详解
    Linux系统-Ubuntu的下载和安装
    5. 基于Embedding实现超越elasticsearch高级搜索
    【学习笔记】AGC035
    【从0-1成为架构师】性能优化的手段
    React之一些函数或者方法的扩展
    C++单例模式与工厂模式
    初阶数据结构:链表相关题目练习(补充)
    Docker应用,从0到0.8
    ABAP BP维护客户cl_md_bp_maintain=>maintain
  • 原文地址:https://blog.csdn.net/u011342224/article/details/127548685