python - 为什么在 python 中评估 boolean 对象需要时间

标签 python performance boolean internals

我使用 timeit 模块比较了这两个代码片段,发现第二个代码片段稍快一些:

~$ python -m timeit —setup "l=[1, 2];k=1" "l[k==1]"
10000000 loops, best of 3: 0.0414 usec per loop
~$ python -m timeit —setup "l=[1, 2];k=1" "l[0 if k==1 else 1]"
10000000 loops, best of 3: 0.0372 usec per loop

由于逻辑相同,我认为评估 boolean 对象比整数等价(True == 1 和 False == 0)花费更多时间,因此我想出了使用以下基准,事实证明我是正确的:

~$ python -m timeit —setup "l=range(1000)" "l[False]"
10000000 loops, best of 3: 0.0411 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[False]"
10000000 loops, best of 3: 0.0394 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[False]"
10000000 loops, best of 3: 0.0416 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[True]"
10000000 loops, best of 3: 0.0428 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[True]"
10000000 loops, best of 3: 0.0394 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[True]"
10000000 loops, best of 3: 0.0393 usec per loop
~$ 
~$
~$ python -m timeit —setup "l=range(1000)" "l[0]"
10000000 loops, best of 3: 0.0232 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[0]"
10000000 loops, best of 3: 0.0232 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[0]"
10000000 loops, best of 3: 0.0232 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[1]"
10000000 loops, best of 3: 0.0232 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[1]"
10000000 loops, best of 3: 0.0232 usec per loop
~$ python -m timeit —setup "l=range(1000)" "l[1]"
10000000 loops, best of 3: 0.0232 usec per loop

但我不知道根本原因是什么。我的意思是为什么评估 TrueFalse 需要更多时间?在基准测试中,我还注意到了另一件神秘的事情。在基准测试的第一部分中,结果存在变化,而第二部分的数字稳定。

最佳答案

对于l[k==1]l[0 if k==1 else 1],你的时间不够长。你看到的差异在你从随机变化中得到的范围内。我不确定哪种形式最终更快,但更长时间的试验显示出相反的效果:

>>> timeit.timeit('l[k==1]', 'l=[1,2];k=1', number=100000000)
10.782931089401245
>>> timeit.timeit('l[0 if k==1 else 1]', 'l=[1,2];k=1', number=100000000)
11.140317916870117

l[0 if k==1 else 1] 出乎意料地很有竞争力,因为 l[k==1] 没有达到 fast path对于 BINARY_SUBSCR 操作码:

TARGET_NOARG(BINARY_SUBSCR)
{
    w = POP();
    v = TOP();
    if (PyList_CheckExact(v) && PyInt_CheckExact(w)) {
        /* INLINE: list[int] */
        Py_ssize_t i = PyInt_AsSsize_t(w);
        if (i < 0)
            i += PyList_GET_SIZE(v);
        if (i >= 0 && i < PyList_GET_SIZE(v)) {
            x = PyList_GET_ITEM(v, i);
            Py_INCREF(x);
        }
        else
            goto slow_get;
    }
    else
      slow_get:
        x = PyObject_GetItem(v, w);

在你的第二个测试中,有一个额外的因素,在 Python 2 中,True 是一个内置的变量查找,而 1 是一个更快的 LOAD_CONST LOAD_CONST 仅对代码对象的 co_consts 元组进行索引,而内置查找需要两次字典查找。

关于python - 为什么在 python 中评估 boolean 对象需要时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35320435/

相关文章:

python - 三个嵌套的 for 循环会降低性能

python - 收到意外的关键字参数 'pk'

python - AWS boto3 get_object 调用的 IfMatch 参数如何工作?

python - (Python) 单链表 - Leetcode

database - VIEW 与 SQL 语句的性能

c++ - 我正在寻找可以在图形编辑程序中进行的任何优化

python - 递归查找具有扩展名的所有文件

java - 将变量从 jBoolean 类型转换为 bool

java - 无法更改方法中的 boolean 值

Java 说这个方法有一个构造函数名称