美文网首页IT狗工作室视觉艺术
Python的openpyxl性能加速

Python的openpyxl性能加速

作者: 铁甲万能狗 | 来源:发表于2020-04-24 20:17 被阅读0次

    openpyxl是所有解析操作excel文件的python库,最受欢迎的扩展之一,因为它的底层lxml是用Cython实现的,读取大型的Excel文件的性能非常出色。

    本片示例是读取一个具有一个接近87万记录的Excel表格,并将所有记录加载到Cython扩展类型的list中,需要强调的是Openpyxl加载工作簿使用最小的时间,一定要使用只读模式。



    在load_workbook函数中指定read_only = True即可,如下所示:

    wb=openpyxl.load_workbook(filename,read_only=True)
    

    反例演示

    下面的代码是一个非常低效的实现,我们分析一下代码,我们从load_workbook函数加载完成后我们得到Workbook对象

    从Workbook对象中我们可以得到Sheet对象-ws ,但在遍历操作中使用Sheet对象的max_row和max_column属性不是一个明智的选择,因为excel工作表实际上可能比它们看起来更大,并且最终您要遍历许多空单元格。

    from openpyxl import load_workbook
    
    def read_excel():
        
        wb=load_workbook("./Vegetable_Fruits.xlsx",read_only=True)
    
        ws=wb['sheet1']
    
        data=list()
        
        maxRow=ws.max_row+1
        maxCol=ws.max_column
        
        for row in range(1,maxRow):
            neRow=[]
            for col in range(0,maxCol):
                neRow.append(ws[row][col].value)
            if len(neRow):
                data.append(neRow)
        return data
    

    我们对上面函数做些修改,将maxRow的记录指定为1000,也就是我们仅读取1000条记录,看看时间消耗77s,那么我们推算一下如果读取完868,966条记录需要的时间67,605秒。

    我们对上面的代码做一些修改,我们将Sheet对象的max_rows属性和max_column属性替换为rows,

    from openpyxl import load_workbook
    
    def read_excel():
        
        wb=load_workbook("./Vegetable_Fruits.xlsx",read_only=True)
    
        ws=wb['sheet1']
        data=[]
        for row in ws.rows:
            neRow=[]
            for cell in row:
                neRow.append(cell.value)
            if len(neRow):
                data.append(neRow)
        return data
    

    恩,时间开销是非常悬殊的,修改后的代码,获取excel工作捕的接近87万记录,时间开销35秒,而修改之前的代码获取代1000条记录要消耗77.8秒



    要使openpyxl获取速度最快的读取速度,不应该在每一行的循环中进行如下的操作

    • 查找列标题
    • 调用Sheet对象的max_row属性或max_column属性,这操作开销异常巨大
    • 使用A坐标风格访问单元格,例如ws["AB" + str(i)]

    上面的代码,其实我们还可以做进一步的优化,我们可以 使用openpyxl内置的迭代器,只要通过enumerate方法传入Sheet对象的rows属性,进而简直告知openpyxl调用其他内部的迭代器,因为Openpyxl的内部迭代器是由C代码所写,因此具有绝代的访问性能优势。

    而且我们也使用Cython代码对上面的代码进一步优化

    %%cython
    from openpyxl import load_workbook
    
    cpdef list read_excel_cy2(str filename):
        
        wb=load_workbook(filename,read_only=True)
    
        ws=wb['sheet1']
    
        cdef list data=list(),neRow
        cdef int rdx,cdx
        
        
        for rdx,row in enumerate(ws.rows):
            neRow=[]
            for cdx,cell in enumerate(row):
                neRow.append(cell.value)
            if len(neRow):
                data.append(neRow)
        return data
    

    这里使用Cython对函数中的某些计算变量进行类型静态化总能快1-2s


    小结

    要openpyxl在读取速度上获取最佳的速度,受很多因素影响,例如设备I/O资源使用情况,我们在算法逻辑上做到如下几点

    • 调用load_workbook时候使用只读模式
    • 使用Cython对循环计算变量进行C类型静态化
    • 在循环中调用尽可能少地起作用,并将中间数据存储在变量中。 它可能会使代码有点笨拙,但它往往会更高效
    • 上文提到的注意事项。

    做到这些,可以使您的代码更具可读性(但这比起第1点和第2点而言是锦上添花)。 Python关于什么是变量和什么是函数也可能是模棱两可的。 但通常来说,中间变量适合于多个函数的调用。对于I/O密集型的代码加速而言,Cython是力不从心的,此时,我们更多地考虑使用异步编程模式,或多线程模式来进一步提升读取速度。

    相关文章

      网友评论

        本文标题:Python的openpyxl性能加速

        本文链接:https://www.haomeiwen.com/subject/coikehtx.html