【问题标题】:Why the performance difference between `|` and `or` different for different values?为什么 `|` 和 `or` 之间的性能差异对于不同的值不同?
【发布时间】:2019-10-24 08:26:21
【问题描述】:

我在给运营商计时性能,我发现了这个:

>>> timeit.timeit("10000000<2 or 10000000>1000",number=10000000)
0.4213107880004827
>>> timeit.timeit("(10000000<2) | (10000000>1000)",number=10000000)
0.5472174039969104

>>> timeit.timeit("1000<200000 or 100>1000",number=10000000)
0.26014828799998213
>>> timeit.timeit("(1000<200000) | (100>1000)",number=10000000)
0.49938497000039206

尽管有时差异很小,但or 在这些大量比较中始终优于|(我不确定这是不是因为数量过多)。

然后:

>>> timeit.timeit("0 or 1",number=10000000)
Out[134]: 0.17863203100023384
>>> timeit.timeit("0 | 1",number=10000000)
Out[135]: 0.06668136799999047

>>> timeit.timeit("00000 | 111111",number=10000000)
Out[136]: 0.06739834499967401
>>> timeit.timeit("00000 or 111111",number=10000000)
Out[137]: 0.1818816989998595

>>> timeit.timeit("True or False",number=10000000)
Out[138]: 0.12497510200046236
>>> timeit.timeit("True | False",number=10000000)
Out[139]: 0.06938139100020635

>>> timeit.timeit("False | True",number=10000000)
Out[140]: 0.0667262490005669
>>> timeit.timeit("False or True",number=10000000)
Out[141]: 0.1443343150003784

发生了什么事?这是预期的吗?我相信| 总是检查两个操作数,即使第一个计算结果为True。所以至少对于第一个操作数是True 的情况,or 不应该一直更快吗?

【问题讨论】:

  • | 是按位或,or 是逻辑或。他们是两个不同的运算符。
  • 是的,我明白了。但是为什么在某些情况下bitwise 更快,而在其他情况下logical?它所比较的​​只是TruthyFalsy
  • 因为它没有比较 Truthy 和 Falsy。它执行按位运算。
  • 好的,所以|TrueFalse(实际上是1 和0)之间执行按位运算,orTrueFalse 之间执行逻辑运算。那么他们的表现不应该在所有情况下都保持一致吗?例如对于整数包含检查,1 in range(1,5) 总是比0&lt;1&lt;5 慢,因为它们的工作方式不同,那为什么不在这里呢?
  • or 将在第一个真实部分停止,因此不必评估任何后续部分。 | 需要这两个部分,并对其执行计算,然后然后仍然评估该计算的结果。

标签: python performance logical-operators boolean-logic


【解决方案1】:

或和|根本不是同一个运算符。

or 执行逻辑快捷方式或而 | 执行有点明智或

result = expression1 or expression2 

等同于

if bool(expression1):
    result = expression1
else:
    result = expression2

所以如果 expression1 为真,则甚至不计算 expression2

而:

结果 = 表达式1 |表达式2

执行有点明智或两个值。所以 expression1 和 expression2 必须产生整数。 (True 被解释为整数 1)

看一下跟随输出的例子

In [8]: "{0:b}".format(0b100 | 0b001)                                           
Out[8]: '101'

In [9]: "{0:b}".format(0b100 or 0b001)                                          
Out[9]: '100'

说明: 如果| / 'or' 右侧的运算符快速求值,则 它可能会'|'更快,因为它会创建无分支代码。

另一方面,如果右侧的运算符是 CPU 密集型的,而左侧有时为真有时为假,那么 or 会更快。

在您的示例中,右侧是一个简单的整数,因此| 可能会快一点。 (与我在最初的回答中所说的相反)

几乎没有执行时间差异的微小操作必须一遍又一遍地计时。假设在一天中的不同时间对它们进行数百次计时。两者兼得。

timeit 的问题在于,您在操作系统上执行 python,该操作系统运行多个进程并且您没有 100% 可预测的环境。

所以我会非常小心地解释运行时的微小差异。

【讨论】:

  • “所以我同意你的假设,通常or 应该比| 快”——这不符合逻辑。事实上,在不知道这些操作如何在内部实现的细节的情况下,这些操作中的哪一个在现代机器上更快并不明显。根据你的给出的描述,| 应该比or 快一点,因为它是无分支的。当然在实际实现中是不同的。
  • or/|右边的表达式为右边的简单表达式。 '|'应该更快(无分支)。对于 CPU 密集型操作员 or 应该更快
  • “它取决于右侧的表达式”——是的,但该表达式是对单个整数的简单逻辑运算。
  • 感谢康拉德。我调整了我的答案
猜你喜欢
  • 2011-02-27
  • 1970-01-01
  • 2015-02-12
  • 2020-08-16
  • 2018-07-25
  • 2021-09-24
  • 2012-11-02
  • 2020-07-09
  • 2022-01-25
相关资源
最近更新 更多