【问题标题】:Optimising `__getitem__` and `__setitem__` for a sparse array in Python在 Python 中为稀疏数组优化 `__getitem__` 和 `__setitem__`
【发布时间】:2011-07-24 18:42:40
【问题描述】:

我正在编写自己的稀疏(一维)数组类,但遇到了一些性能问题。分析表明瓶颈之一是我的__getitem____setitem__ 实现,特别是,似乎罪魁祸首之一可能是我对isinstance 的使用。目前,我在__getitem__ 中有 5 次调用 isinstance,我从 cProfile 中获得以下数据(摘录):

ncalls tottime percall cumtime percall filename:lineno(function) 86462 0.076 0.000 0.084 0.000 sparse.py:107(__setitem__) 189730 0.147 0.000 0.166 0.000 sparse.py:45(__getitem__) 276366 0.028 0.000 0.028 0.000 {内置方法isinstance}

我的__getitem__ 实现了切片和数组访问,所以我怀疑某种类型的自省必要的......但我想知道@987654327 @真的是最好的方法吗?

另一方面,我的__setitem__ 不支持切片(无论如何只调用一次isinstance),所以我不知道如何让它更快。每行分析数据如下:

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
   108                                              @profile
   109                                              def __setitem__(self, key, value):
   110     88705       121012      1.4     23.0         if not isinstance(key, int):
   111                                                      raise TypeError('list indices must be be integers')
   112                                                  
   113     88705        95905      1.1     18.3         if key >= self._length:
   114                                                      raise IndexError('list index out of range')
   115                                                  
   116     88705        85328      1.0     16.2         if key < 0:
   117                                                      key = self._length + key
   118                                                  
   119     88705        89186      1.0     17.0         if value == self._default:
   120     35043        37087      1.1      7.1             if key in self._entries:
   121     35042        39359      1.1      7.5                 del self._entries[key]
   122                                                  else:
   123     53662        57527      1.1     10.9             self._entries[key] = value

(我也愿意接受建议使用合适的快速稀疏数组 Python 模块的答案。我的要求之一是能够仅快速迭代非零条目的(键)。)

【问题讨论】:

    标签: python optimization


    【解决方案1】:

    要回答您的直接问题,isinstance() 的调用速度较慢,因为该名称是全球性的。您只需将isinstance=isinstance 添加到__setitem__() 的签名即可显着加快速度,如下所示:

    def __setitem__(self, key, value, isinstance=isinstance):
        # und so weiter
    

    这会将全局名称转换为本地名称,这在运行时查找起来明显更快。作为奖励,本地名称在函数定义时绑定到内置的isinstance 函数,因此在调用变量时没有初始化变量的开销。

    然而,正如其他人所指出的,在您显示的代码中,您可能甚至不需要该调用,但可以简单地尝试将密钥转换为int,或者甚至跳过那个。 (但是,将int=int 添加到您的方法签名中可以稍微提高速度,因为int 也是一个全局名称......)

    但如果您要进行错误检查,您还应该测试索引是否小于零。如果长度是 50 并且用户想要项目 -100 怎么办? :-)

    【讨论】:

      【解决方案2】:

      你为什么不尝试替换...

      if not isinstance(key,int):
          raise TypeError('list indices must be integers')
      

      ...与...

      key = int(key)
      

      我相信这最终会是一个更快的操作,而且它似乎会更灵活,因为如果有人将一些可以转换为整数的东西交给你的函数,它仍然可以工作。


      您也可以考虑完全检查它们的键类型。只需记录使用 int 以外的任何内容都是未定义的行为,然后用户有责任确保他们正确使用它。

      【讨论】:

        【解决方案3】:

        如何摆脱异常?

        
        def __setitem__(self, key, value):
           # This checks that:
           # - key is an integer (or can be converted to an integer)
           # - key is replaced by an appropriate positive value when < 0
           # - key is made = self._length when key >= self._length (not exactly as before)
           key = slice(key).indices(self._length)[1]
        
           if value == self._default:
               self._entries.pop(key, None) # assuming _entries is of type dict
           else:
               self._entries[key] = value
        

        【讨论】:

        • 谢谢,但使用pop 似乎比ifdel 慢...可能是因为它是一个函数调用?
        【解决方案4】:

        改用assert

        if not isinstance(key, int):
           raise TypeError('list indices must be be integers')
        

        它比“if ....: raise exception”更快

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-03-03
          • 2015-07-04
          • 2018-08-22
          • 2021-04-27
          相关资源
          最近更新 更多