我发现我经常在嵌套循环中使用静态字符串访问Python字典。我猜想Python需要为每次访问散列字符串,这可能会影响性能。
例如:
for d in large_list_of_dicts:
for d2 in d['trees']:
v = d2['leaves']
Cython是否将这些静态字符串键散列为散列值(仅一次)并重用这些散列?如果是这样,是否可以显着提高此类循环的性能?
答案 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)-并不是很多,但总比没有好。