2016-12-27 2 views
2

У меня есть вычислительно дорогой цикл, чтобы пройти через Python. В общем, я зацикливаю около 2 миллионов раз, и каждый раз добавляю новый ключ к растущему словарю со списком в качестве значения. Т.е.,Python/Cython добавление словаря является узким местом

for i in xrange(600): 
    d = {} 

    for i in xrange(3200): 
     # execute some logic 
     ... 

     # add to dict 
     new_key = "some-str" 
     d[new_key] = [0.0, 1.0, 2.0] 

    # do some other stuff 
    ... 

Я профилированный свой код, и операция, при которой я добавляю новый список ключ + в словарь является огромным препятствием. Эта единственная операция занимает ~ 18% от времени выполнения на 1e-06 секунд за операцию.

Есть ли способ ускорить эту операцию в Cython/Python? Я попытался изменить d на defaultdict, но это было медленнее. Я также пробовал различные операции с списком, такие как .extend, но приведенная выше реализация - это самый быстрый подход, который я смог найти.

+0

Я могу предложить вам использовать кортеж вместо списка 'd [new_key] = (0.0, 1.0, 2.0,)' потому что tuple неизменный сборщик мусора не будет отслеживать его, и это может улучшить вашу скорость – latsha

+0

'cython' still должен использовать вызовы Python для добавления в словарь. Не ходите по этому маршруту только из-за этой операции. – hpaulj

+0

Спасибо за комментарии. @hpaulj, что было бы лучшей структурой данных для хранения этих данных? – deef

ответ

0

Так вот итеративное создание словаря:

In [5]: adict = {} 
In [6]: for i in range(4): 
    ...:  adict[i] = list(range(i,i+4)) 
In [7]: adict 
Out[7]: {0: [0, 1, 2, 3], 1: [1, 2, 3, 4], 2: [2, 3, 4, 5], 3: [3, 4, 5, 6]} 

numpy В числовой работе мы часто рекомендуем добавление значения в список, и сделать массив из него в конце. Эквивалентом словаря является:

In [8]: alist = [] 
In [9]: for i in range(4): 
    ...:  alist.append((i, list(range(i,i+4)))) 
In [10]: alist 
Out[10]: [(0, [0, 1, 2, 3]), (1, [1, 2, 3, 4]), (2, [2, 3, 4, 5]), (3, [3, 4, 5, 6])] 
In [11]: dict(alist) 
Out[11]: {0: [0, 1, 2, 3], 1: [1, 2, 3, 4], 2: [2, 3, 4, 5], 3: [3, 4, 5, 6]} 

Выполнение некоторых таймингов с использованием Ipython timeit.

Первый прямой итерационный словарь:

In [12]: %%timeit 
    ...: adict = {} 
    ...: for i in range(1000): 
    ...: adict[i] = list(range(i,i+4)) 
    ...: 
1000 loops, best of 3: 1.67 ms per loop 

Список Append в основном то же самое время:

In [13]: %%timeit 
    ...: alist = [] 
    ...: for i in range(1000): 
    ...: alist.append((i,list(range(i,i+4)))) 

1000 loops, best of 3: 1.79 ms per loop 

Добавление dict(alist) является незначительное увеличение времени

In [14]: %%timeit 
    ...: alist = [] 
    ...: for i in range(1000): 
    ...: alist.append((i,list(range(i,i+4)))) 
    ...: adict = dict(alist) 
1000 loops, best of 3: 1.93 ms per loop 

It что если вам нужно создавать значения в цикле, это не имеет большого значения собираете ли вы их в словаре или списке.

Если у вас уже есть подходящий список, то быстро преобразовать его в словарь. Но он не платит, чтобы создать список в качестве промежуточного шага.

Словарь update также является хорошим способом добавления большого количества значений в словарь, но сначала вам нужен исходный словарь.

+0

Спасибо за это. Я согласен, что мне не удалось найти гораздо лучший способ добавить значения в цикл. Дикты/списки сопоставимы, как вы указали. – deef

Смежные вопросы