Cython是否将静态字典键编译为其哈希值?

时间:2019-03-06 13:05:30

标签: python dictionary optimization cython

我发现我经常在嵌套循环中使用静态字符串访问Python字典。我猜想Python需要为每次访问散列字符串,这可能会影响性能。

例如:

for d in large_list_of_dicts:
    for d2 in d['trees']:
        v = d2['leaves']

Cython是否将这些静态字符串键散列为散列值(仅一次)并重用这些散列?如果是这样,是否可以显着提高此类循环的性能?

1 个答案:

答案 0 :(得分:1)

Cython在这里不会表现出任何魔力:它只会delegate调用PyDict_GetItemWithError,这与Python解释器的作用基本相同(但可能会更快)。

但是,一个unicode对象(我假设我们正在谈论Python3字符串)会缓存其哈希值(在PyUnicodeObject.hash-member field中),因此该值仅需计算一次-这很有意义,因为unicode-对象是不可变的,这意味着哈希不能更改。

the CPython code负责哈希计算/缓存:

#define _PyUnicode_HASH(op)                             \
(((PyASCIIObject *)(op))->hash)
...

static Py_hash_t
unicode_hash(PyObject *self)
{
    ...
    // if hash already calculated, return cached value
    if (_PyUnicode_HASH(self) != -1)
        return _PyUnicode_HASH(self);
    ...
    // else caclculate hash, cache value, return it
    x = _Py_HashBytes(PyUnicode_DATA(self),
                      PyUnicode_GET_LENGTH(self) * PyUnicode_KIND(self));
    _PyUnicode_HASH(self) = x;
    return x;
}

因此,如您所见,Cython无需避免哈希重新计算-CPython已经完成了此优化。

通过在此处使用Cython,可以赢得10%到30%的奖金,因为它可以省去这部分代码的解释程序(例如,参见此SO-post)-并不是很多,但总比没有好。