【问题标题】:Does Cython compile static dict keys to their hash values?Cython 是否将静态字典键编译为其哈希值?
【发布时间】:2019-03-06 13:05:29
【问题描述】:

我发现我在嵌套循环中非常频繁地使用静态字符串访问 Python 字典。我猜 Python 需要对每次访问的字符串进行哈希处理,这可能会影响性能。

例如:

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

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

【问题讨论】:

  • 我不熟悉 Cython,但即使在常规 Python 中,也最多会为给定的字符串对象计算一次哈希——它被缓存在对象中。我无法想象 Cython 会放弃这样一个基本的优化。
  • @jasonharper 谢谢,我没有意识到这一点。所以听起来在这里使用 Cython 并没有什么好处。

标签: python dictionary optimization cython


【解决方案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) - 不是很多,但总比没有好。

【讨论】:

    猜你喜欢
    • 2018-07-31
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    • 2012-12-13
    • 2018-04-15
    • 2015-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多