функция поиска слишком медленная записькласс python оптимизация - PullRequest
1 голос
/ 27 февраля 2020

Dict() занимают много памяти, поэтому я попытался использовать другой способ. используя dataobject, что заняло 6Gb, теперь 700M. Тем не менее, когда дело доходит до поиска, это очень медленно, что я реализовал

Я знаю, что не могу конкурировать с python, но, по крайней мере, сделать его лучше

Пожалуйста, если у вас есть идеи возможно Cpython

Во-первых: я пробовал цепочечные узлы, но все еще медленно

from recordclass import dataobject
class node(dataobject):
      elt1:tuple
      elt2:list
      _next:str


def find(n1,elt1): 
  if n1 is None: 
    return None 
  if n1.elt1==elt1: 
    #print(n1.elt2)
    return n1.elt2
  else: 
    return find(n1._next,elt1) 
#or

def find1(n1,elt1):
  while n1 is not None:
    if n1.elt1==elt1: 
      #print(n1.elt2)
      return n1.elt2
    else:
      n1=n1._next

n1=None 
daca=dict()
for i in range(0,100,2): 
  n1=node(i,i+1,n1) 
  daca[i]=i+1


#find(n1,12) compared to daca[12], dictionary is 7 times faster than find

секунда: я пытался добавить все узлы в список, но все еще медленно


from recordclass import dataobject
class node(dataobject):
      elt1:tuple
      elt2:list


def find(n1,elt):
  return list(filter(lambda x: x.elt1==elt ,n1))


n1=[] 
daca=dict()
for i in range(0,100,2): 
  n1.append(node(i,i+1) )
  daca[i]=i+1

#find(n1,12) compared to daca[12], dictionary is 7 times faster than find

1 Ответ

1 голос
/ 28 февраля 2020

Трудно укусить python диктовать для сохранения значений ключом.

Библиотека классов записей может помочь уменьшить объем памяти следующим образом.

from recordclass import make_arrayclass, litelist
from random import randint

Модуль tracemalloc используется для оценки объема памяти:

import tracemalloc
class Tracer:
    def __enter__(self):
        if tracemalloc.is_tracing():
            raise ValueError('nesting tracemalloc is not allowed')
        self.allocated = None
        tracemalloc.start()
        return self
    def __exit__(self, exc_type, exc_value, exc_traceback):
        current, peak = tracemalloc.get_traced_memory()
        tracemalloc.stop()
        self.allocated = current

Сначала оценим «вес» части дикта:

with Tracer() as t0:
   d0 = {i:None for i in range(5_000_000)}
print("dict:", t0.allocated // 1_000_000, 'Mb')
del d0, t0

Результат - 307 Мб

Во-вторых, давайте оценим объем памяти словаря с 5_000_000 записей. Ключ представляет собой тройку случайных целых чисел, значение представляет собой список из 6 случайных целых чисел.

with Tracer() as t1:
    d1 = {}
    for i in range(N):
        key = (randint(0,N), randint(0,N), randint(0,N))
        val = [randint(0,N) for i in range(10)]
        d1[key] = val
print("regular:", t1.allocated // 1_000_000, 'Mb')
del d1, t1

Результат составляет 3387 Мб. Таким образом, часть диктата относительно мала.

Чтобы уменьшить объем памяти кортежей и списков, можно использовать make_arrayclass и litelist из библиотеки recordclass:

Triple = make_arrayclass("Triple", 3, hashable=True)

with Tracer() as t2:
    d2 = {}
    for i in range(N):
        key = Triple(randint(0,N), randint(0,N), randint(0,N))
        val = litelist([randint(0,N) for i in range(6)])
        d2[key] = val
print("recordclass:", t2.allocated // 1_000_000, 'Mb')
del d2, t2

Результат - 2107 Мб. Таким образом, это экономит около 1 Гб.

PS: используется Python 3.7.

...