【问题标题】:search function is too slow recordclass python optimization搜索功能太慢recordclass python优化
【发布时间】:2020-06-11 00:54:10
【问题描述】:

Dict() 会消耗内存,所以我尝试使用其他方式。使用 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

【问题讨论】:

    标签: python-3.x performance optimization compiler-optimization cpython


    【解决方案1】:

    很难用python dict来按键搜索值。

    Recordclass 库可以通过以下方式帮助减少内存占用。

    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
    

    首先估计dict部分的“权重”:

    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 Mb

    其次,让我们用 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 Mb。所以dict的部分比较小。

    为了减少元组和列表的内存占用,可以使用来自recordclass 库的make_arrayclasslitelist

    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 Mb。所以这节省了大约 1 Gb。

    P.S.:使用的是 Python 3.7。

    【讨论】:

    • 非常感谢。但是,我现在正在做的是使用 hdf5,因为您可以直接进入您想要的路径。如果您对此感兴趣,请让我知道,我会将代码上传到 github。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多