IT狗工作室视觉艺术

Python的openpyxl性能加速

2020-04-24  本文已影响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获取速度最快的读取速度,不应该在每一行的循环中进行如下的操作

上面的代码,其实我们还可以做进一步的优化,我们可以 使用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资源使用情况,我们在算法逻辑上做到如下几点

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

上一篇下一篇

猜你喜欢

热点阅读