Почему win32com намного медленнее xlrd? - PullRequest
2 голосов
/ 03 июня 2010

У меня тот же код, написанный с использованием win32com и xlrd. xlrd преобразует алгоритм менее чем за секунду, в то время как win32com занимает минуты.

Вот win32com:

def makeDict(ws):
"""makes dict with key as header name, 
   value as tuple of column begin and column end (inclusive)"""
wsHeaders = {} # key is header name, value is column begin and end inclusive
for cnum in xrange(9, find_last_col(ws)):
    if ws.Cells(7, cnum).Value:
        wsHeaders[str(ws.Cells(7, cnum).Value)] = (cnum, find_last_col(ws))
        for cend in xrange(cnum + 1, find_last_col(ws)): #finds end column
            if ws.Cells(7, cend).Value:
                wsHeaders[str(ws.Cells(7, cnum).Value)] = (cnum, cend - 1)
                break
return wsHeaders

и xlrd

def makeDict(ws):
"""makes dict with key as header name, 
   value as tuple of column begin and column end (inclusive)"""
wsHeaders = {} # key is header name, value is column begin and end inclusive
for cnum in xrange(8, ws.ncols):
    if ws.cell_value(6, cnum):
        wsHeaders[str(ws.cell_value(6, cnum))] = (cnum, ws.ncols)
        for cend in xrange(cnum + 1, ws.ncols):#finds end column
            if ws.cell_value(6, cend):
                wsHeaders[str(ws.cell_value(6, cnum))] = (cnum, cend - 1)
                break
return wsHeaders

Ответы [ 3 ]

12 голосов
/ 04 июня 2010

(0) Вы спросили: «Почему win32com намного медленнее, чем xlrd?» ... этот вопрос немного похож на "Ты перестал бить свою жену?" --- оно основано на предположении, которое может быть неверным; win32com был написан на C блестящим программистом, но xlrd был написан на чистом Python обычным программистом. Реальное различие заключается в том, что win32com должен вызывать COM, который включает межпроцессное взаимодействие и было написано вами самим, а xlrd читает файл Excel напрямую. Более того, в сценарии есть четвертая сторона: ВЫ. Пожалуйста, продолжайте читать.

(1) Вы не показываете нам источник функции find_last_col(), которую вы периодически используете в коде COM. В коде xlrd вы всегда рады использовать одно и то же значение (ws.ncols). Таким образом, в коде COM вы должны позвонить find_last_col(ws) ONCE и затем использовать возвращенный результат. Обновление См. ответ на отдельный вопрос о том, как получить эквивалент Sheet.ncols xlrd из COM.

(2) Доступ к каждому значению ячейки ДВАЖДЫ замедляет оба кода. Вместо

if ws.cell_value(6, cnum):
    wsHeaders[str(ws.cell_value(6, cnum))] = (cnum, ws.ncols)

1017 * попробовать *

value = ws.cell_value(6, cnum)
if value:
    wsHeaders[str(value)] = (cnum, ws.ncols)

Примечание: в каждом фрагменте кода есть 2 случая этого.

(3) Совершенно не очевидно, какова цель ваших вложенных циклов, но, похоже, существуют некоторые избыточные вычисления, включающие избыточные выборки из COM. Если вы хотите рассказать нам, чего вы пытаетесь достичь, с помощью примеров, мы могли бы помочь вам сделать это намного быстрее. По крайней мере, извлечение значений из COM один раз и последующая обработка их во вложенных циклах в Python должно быть быстрее. Сколько там столбцов?

Обновление 2 Тем временем маленькие эльфы взяли ваш код с помощью проктоскопа и придумали следующий скрипт:

tests= [
    "A/B/C/D",
    "A//C//",
    "A//C//E",
    "A///D",
    "///D",
    ]
for test in tests:
    print "\nTest:", test
    row = test.split("/")
    ncols = len(row)
    # modelling the OP's code
    # (using xlrd-style 0-relative column indexes)
    d = {}
    for cnum in xrange(ncols):
        if row[cnum]:
            k = row[cnum]
            v = (cnum, ncols) #### BUG; should be ncols - 1 ("inclusive")
            print "outer", cnum, k, '=>', v
            d[k] = v
            for cend in xrange(cnum + 1, ncols):
                if row[cend]:
                    k = row[cnum]
                    v = (cnum, cend - 1)
                    print "inner", cnum, cend, k, '=>', v
                    d[k] = v
                    break
    print d
    # modelling a slightly better algorithm
    d = {}
    prev = None
    for cnum in xrange(ncols):
        key = row[cnum]
        if key:
            d[key] = [cnum, cnum]
            prev = key
        elif prev:
            d[prev][1] = cnum
    print d
    # if tuples are really needed (can't imagine why)
    for k in d:
        d[k] = tuple(d[k])
    print d

который выводит это:

Test: A/B/C/D
outer 0 A => (0, 4)
inner 0 1 A => (0, 0)
outer 1 B => (1, 4)
inner 1 2 B => (1, 1)
outer 2 C => (2, 4)
inner 2 3 C => (2, 2)
outer 3 D => (3, 4)
{'A': (0, 0), 'C': (2, 2), 'B': (1, 1), 'D': (3, 4)}
{'A': [0, 0], 'C': [2, 2], 'B': [1, 1], 'D': [3, 3]}
{'A': (0, 0), 'C': (2, 2), 'B': (1, 1), 'D': (3, 3)}

Test: A//C//
outer 0 A => (0, 5)
inner 0 2 A => (0, 1)
outer 2 C => (2, 5)
{'A': (0, 1), 'C': (2, 5)}
{'A': [0, 1], 'C': [2, 4]}
{'A': (0, 1), 'C': (2, 4)}

Test: A//C//E
outer 0 A => (0, 5)
inner 0 2 A => (0, 1)
outer 2 C => (2, 5)
inner 2 4 C => (2, 3)
outer 4 E => (4, 5)
{'A': (0, 1), 'C': (2, 3), 'E': (4, 5)}
{'A': [0, 1], 'C': [2, 3], 'E': [4, 4]}
{'A': (0, 1), 'C': (2, 3), 'E': (4, 4)}

Test: A///D
outer 0 A => (0, 4)
inner 0 3 A => (0, 2)
outer 3 D => (3, 4)
{'A': (0, 2), 'D': (3, 4)}
{'A': [0, 2], 'D': [3, 3]}
{'A': (0, 2), 'D': (3, 3)}

Test: ///D
outer 3 D => (3, 4)
{'D': (3, 4)}
{'D': [3, 3]}
{'D': (3, 3)}
2 голосов
/ 03 июня 2010

COM требует общения с другим процессом, который фактически обрабатывает запросы. xlrd работает непосредственно над структурами данных.

0 голосов
/ 04 июня 2010

Думал об этом, когда я ложился спать прошлой ночью, и в итоге использовал это. Гораздо лучшая версия моего оригинала:

def makeDict(ws):
"""makes dict with key as header name, 
   value as tuple of column begin and column end (inclusive)"""
wsHeaders = {} # key is header name, value is column begin and end inclusive
last_col = find_last_col(ws)

for cnum in xrange(9, last_col):
    if ws.Cells(7, cnum).Value:
        value = ws.Cells(7, cnum).Value
        cstart = cnum
    if ws.Cells(7, cnum + 1).Value:
        wsHeaders[str(value)] = (cstart, cnum) #cnum is last in range
return wsHeaders
...