gspread update_cell非常慢

时间:2016-07-12 15:54:18

标签: python python-3.x google-sheets gspread

我有两个谷歌电子表格:

QC-许多列,我想检查第4列中的值是否出现在第二个电子表格lastEdited_PEID中;如果确实如此,就会把'宾果!'在找到值的同一行的第14列

lastEdited-一列,长值的电子表格

我用以下代码实现了这个目标:

#acces the documents on Drive
QC = gc.open_by_key("FIRST KEY").sheet1
lastEdited = gc.open_by_key("SECOND KEY").sheet1

#get values from columns and convert to lists 
QC_PEID = QC.col_values(4)
lastEdited_PEID = lastEdited.col_values(1)

#iterate by rows and check if value from each row appears in the second document
for value in QC_PEID:
    ind = QC_PEID.index(value)
    if value in lastEdited_PEID:
        QC.update_cell(ind, 14, 'Bingo!')

所以它完成了这项工作,但却非常缓慢(大约5分钟)。我担心速度,因为我必须执行大约50个电子表格的操作(平均每行6000行)。

我试图在找到时从第二个列表中删除元素(它只能出现一次),循环中包含以下代码:

    for value in QC_PEID:
        ind = QC_PEID.index(value)
        if value in lastEdited_PEID:
            QC.update_cell(ind, 14, 'Bingo!')
            **lastEdited_PEID.remove('value')**

我认为它会让它更快,因为参考列表会更短,但令人惊讶的是它需要更多。

我可以做些什么来加快这个过程?

1 个答案:

答案 0 :(得分:4)

由于gspread是Google Sheet的REST API的包装器,因此您在电子表格上执行的每项操作都会呈现给API的HTTP请求。大多数情况下,这是代码中最慢的部分。如果您想提高性能,您需要弄清楚如何减少与API的交互次数。

在您的代码示例中,每个col_values()调用都会发出一个HTTP请求。这很好。但是,当你迭代单元格值时,循环中会出现update_cell()

for value in QC_PEID:
    ind = QC_PEID.index(value)
    if value in lastEdited_PEID:
        QC.update_cell(ind, 14, 'Bingo!')  # it makes 2 HTTP requests each time

update_cell向API发出两个 HTTP请求(一个用于检索更新单元格所需的信息,另一个用于实际将更新发送到API。)您需要避免使用此方法在你的循环中呼唤。

更好的想法是收集所有更新并批量发送。这是update_cells()方法的用途。

update_cells()需要Cell个对象列表才能进行批量更新。您可以通过致电Worksheet.range()来获取这些内容。

这就是我的想法:

# A utility method
def col_cells(worksheet, col):
    """Returns a range of cells in a `worksheet`'s column `col`."""
    start_cell = self.get_addr_int(1, col)
    end_cell = self.get_addr_int(worksheet.row_count, col)

    return worksheet.range('%s:%s' % (start_cell, end_cell))

QC_PEID = QC.col_values(4)
lastEdited_PEID = set(lastEdited.col_cells(1))  # make the 'in' lookup a bit faster
column_14_cells = col_cells(QC, 14)

has_updates = False
# iterate by rows and check if value from each row appears in the second document
for i, value in enumerate(QC_PEID):
    if value in lastEdited_PEID:
        has_updates = True
        column_14_cells[i].value = 'Bingo!'

if has_updates:
    QC.update_cells(column_14_cells)

我没有运行代码。小心拼写错误。