Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python中最快(访问)类似结构的对象是什么?_Python_Performance_Data Structures - Fatal编程技术网

Python中最快(访问)类似结构的对象是什么?

Python中最快(访问)类似结构的对象是什么?,python,performance,data-structures,Python,Performance,Data Structures,我正在优化一些代码,这些代码的主要瓶颈是运行和访问大量类似结构的对象。目前,为了可读性,我使用namedtuples。但一些使用“timeit”的快速基准测试表明,在性能是一个因素的情况下,这确实是一种错误的方法: 带a、b、c的命名元组: >>> timeit("z = a.c", "from __main__ import a") 0.38655471766332994 >>> timeit("z = b.c", "from __main__ impor

我正在优化一些代码,这些代码的主要瓶颈是运行和访问大量类似结构的对象。目前,为了可读性,我使用namedtuples。但一些使用“timeit”的快速基准测试表明,在性能是一个因素的情况下,这确实是一种错误的方法:

带a、b、c的命名元组:

>>> timeit("z = a.c", "from __main__ import a")
0.38655471766332994
>>> timeit("z = b.c", "from __main__ import b")
0.14527461047146062
使用a、b、c:

>>> timeit("z = a.c", "from __main__ import a")
0.38655471766332994
>>> timeit("z = b.c", "from __main__ import b")
0.14527461047146062
带键a、b、c的词典:

>>> timeit("z = c['c']", "from __main__ import c")
0.11588272541098377
具有三个值的元组,使用常量键:

>>> timeit("z = d[2]", "from __main__ import d")
0.11106188992948773
>>> timeit("z = e[2]", "from __main__ import e")
0.086038238242508669
使用常量键列出三个值:

>>> timeit("z = d[2]", "from __main__ import d")
0.11106188992948773
>>> timeit("z = e[2]", "from __main__ import e")
0.086038238242508669
具有三个值的元组,使用本地键:

>>> timeit("z = d[key]", "from __main__ import d, key")
0.11187358437882722
>>> timeit("z = e[key]", "from __main__ import e, key")
0.088604143037173344
使用本地键列出三个值:

>>> timeit("z = d[key]", "from __main__ import d, key")
0.11187358437882722
>>> timeit("z = e[key]", "from __main__ import e, key")
0.088604143037173344
首先,这些小小的
timeit
测试是否会导致它们无效?我每次都运行了几次,以确保没有随机系统事件将它们抛出,并且结果几乎相同

词典似乎在性能和可读性之间提供了最佳平衡,类排在第二位。这是不幸的,因为,出于我的目的,我还需要对象像序列一样;因此,我选择了namedtuple

列表速度大大加快,但常量键无法维护;我必须创建一组索引常量,即KEY_1=1,KEY_2=2,等等,这也是不理想的


我是坚持这些选择,还是错过了其他选择?

我可能会(a)发明某种特定于工作负载的缓存,并将数据的存储和检索转移到类似memcachedb的进程中,以提高可伸缩性,而不仅仅是性能,或者(b)将其重写为C扩展,使用本机数据存储。可能是一种有序的字典类型

您可以从以下内容开始:
您可以通过添加
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu


你想要一份工作吗?Python31模块中包含了几种可用的实现方式。

几点要点和想法:

  • 您连续多次定时访问同一索引。您的实际程序可能使用随机或线性访问,这将有不同的行为。特别是,将有更多的CPU缓存未命中。使用实际程序可能会得到稍微不同的结果

  • OrderedDictionary是作为
    dict
    的包装器编写的,因此它将比
    dict
    慢。这不是解决办法

  • 你试过新的和旧的课程吗?(新样式类继承自
    对象
    ;旧样式类不继承)

  • 你试过使用或吗?(2020年更新-这两个项目已经停止)

  • 您的内部循环是修改数据还是仅访问数据?在进入循环之前,可以将数据转换为最有效的形式,但在程序的其他地方使用最方便的形式


  • 需要记住的一点是,命名的元组经过优化,可以作为元组访问。如果将访问器更改为
    a[2]
    而不是
    a.c
    ,您将看到与元组类似的性能。原因是名称访问器正在有效地转换为对self[idx]的调用,因此需要支付索引和名称查找的费用

    如果您的使用模式是按名称访问是常见的,而按元组访问则不是常见的,那么您可以编写一个与namedtuple类似的快速等价物,它的作用与此相反:将索引查找延迟到按名称访问。但是,您将在索引查找时付出代价。下面是一个快速实现:

    def makestruct(name, fields):
        fields = fields.split()
        import textwrap
        template = textwrap.dedent("""\
        class {name}(object):
            __slots__ = {fields!r}
            def __init__(self, {args}):
                {self_fields} = {args}
            def __getitem__(self, idx): 
                return getattr(self, fields[idx])
        """).format(
            name=name,
            fields=fields,
            args=','.join(fields), 
            self_fields=','.join('self.' + f for f in fields))
        d = {'fields': fields}
        exec template in d
        return d[name]
    
    但是当必须调用
    \uu getitem\uu
    时,计时非常糟糕:

    namedtuple.a  :  0.473686933517 
    namedtuple[0] :  0.180409193039
    struct.a      :  0.180846214294
    struct[0]     :  1.32191514969
    
    也就是说,与属性访问的
    \uuuu slots\uuu
    类的性能相同(毫不奇怪,事实就是这样),但由于基于索引的访问中的双重查找,会带来巨大的损失。(值得注意的是,
    \uuuuu插槽\uuuuu
    实际上对速度没有多大帮助。它可以节省内存,但没有它们的访问时间几乎相同。)


    第三种选择是复制数据,例如从列表中创建子类,并将值存储在属性和列表数据中。然而,您实际上并没有获得与列表相同的性能。子类化带来了巨大的速度冲击(带来了对纯python重载的检查)。因此,在这种情况下,struct[0]仍然需要0.5s左右的时间(与原始列表的0.18相比),并且您的内存使用量增加了一倍,因此这可能不值得。这个问题已经相当老了(互联网时间),所以我想我今天会尝试复制您的测试,使用常规的CPython(2.7.6)和pypypy(2.2.1)看看各种方法的比较。(我还为命名元组添加了索引查找。)

    这有点像一个微基准测试,所以YMMV,但是pypy似乎比CPython加快了命名元组访问30倍(而字典访问的速度只有3倍)

    Python结果:

    Named tuple with a, b, c:
    0.124072679784
    Named tuple, using index:
    0.0447055962367
    Class using __slots__, with a, b, c:
    0.0409136944224
    Dictionary with keys a, b, c:
    0.0412045334915
    Tuple with three values, using a constant key:
    0.0449477955531
    List with three values, using a constant key:
    0.0331083467148
    Tuple with three values, using a local key:
    0.0453569025139
    List with three values, using a local key:
    0.033030056702
    
    Named tuple with a, b, c:
    0.00444889068604
    Named tuple, using index:
    0.00265598297119
    Class using __slots__, with a, b, c:
    0.00208616256714
    Dictionary with keys a, b, c:
    0.013897895813
    Tuple with three values, using a constant key:
    0.00275301933289
    List with three values, using a constant key:
    0.002760887146
    Tuple with three values, using a local key:
    0.002769947052
    List with three values, using a local key:
    0.00278806686401
    
    PyPy结果:

    Named tuple with a, b, c:
    0.124072679784
    Named tuple, using index:
    0.0447055962367
    Class using __slots__, with a, b, c:
    0.0409136944224
    Dictionary with keys a, b, c:
    0.0412045334915
    Tuple with three values, using a constant key:
    0.0449477955531
    List with three values, using a constant key:
    0.0331083467148
    Tuple with three values, using a local key:
    0.0453569025139
    List with three values, using a local key:
    0.033030056702
    
    Named tuple with a, b, c:
    0.00444889068604
    Named tuple, using index:
    0.00265598297119
    Class using __slots__, with a, b, c:
    0.00208616256714
    Dictionary with keys a, b, c:
    0.013897895813
    Tuple with three values, using a constant key:
    0.00275301933289
    List with three values, using a constant key:
    0.002760887146
    Tuple with three values, using a local key:
    0.002769947052
    List with three values, using a local key:
    0.00278806686401
    

    这个问题可能很快就会过时。显然,cpythondev对通过属性名访问命名元组值的性能做出了重大改进。这些更改计划于2019年10月底发布


    请参阅:和。

    如果性能如此重要,为什么不使用C?@Skilldrick:这只是大型程序的一小部分,而大型程序得益于使用Python编写。将此部分重写为C扩展是一种选择,但有些不可取,因为其他代码也会涉及数据,这会使事情变得有点复杂。绩效很重要,但不是那么关键;如果不是因为可维护性的降低,我对列表提供的4倍改进非常满意。在我决定走哪条路之前,我只是在寻找其他的选择;我没有过早地优化。这是一个非常紧密的循环,其中