我试图弄清楚“in”运算符为何比检查值是否在某些间隔范围内提供更好的性能。
为什么第一段代码比第二段慢?直觉上我预计第一段代码会更快(3 个布尔运算 + 4 个整数比较),因为它只检查每个字节的每个间隔的边界,而第二个代码将迭代我们的字符集的整个数组(比较针对长度=100 的数组中的每个整数)。
import random
data = random.randbytes(1000000)
a_lower, a_upper, b_lower, b_upper = (9, 13, 32, 126)
%timeit [((x >= a_lower and x <= a_upper) or (x >= b_lower and x <= b_upper)) for x in data]
结果约为 82 毫秒
import string
import random
data = random.randbytes(1000000)
charset = bytearray(string.printable, "ascii")
%timeit [x in charset for x in data]
结果约为 44 毫秒
我研究了 bytesarray“in”的 CPython 实现,看起来它最终到达了 memchr
我剩下的唯一理论是,第二段代码中可能有更多的函数调用,最终占用的 CPU 时间比“基本操作”数量之间的差异还要多。
我认为这是因为第二个解决方案可以使用
memchr
,它是纯C,因此比第一个解决方案中的Python比较快得多。如果您通过 numpy 执行第一个解决方案,您甚至比第二个解决方案更快(在我的机器上大约 100 倍):
import random
import numpy as np
data = random.randbytes(1000000)
a_lower, a_upper, b_lower, b_upper = (9, 13, 32, 126)
data = np.frombuffer(data, dtype=np.uint8)
%timeit ((data >= a_lower) & (data <= a_upper)) | ((data >= b_lower) & (data <= b_upper))