Python 为什么str.strip()比str.strip快那么多?
使用可以通过两种方式在空白处进行拆分。您可以发出不带参数的调用,Python 为什么str.strip()比str.strip快那么多?,python,string,performance,python-3.x,python-internals,Python,String,Performance,Python 3.x,Python Internals,使用可以通过两种方式在空白处进行拆分。您可以发出不带参数的调用,str.strip(),该调用默认使用空白分隔符,也可以显式地为参数提供str.strip(“”) 但是,为什么这些功能在计时时表现如此不同 使用带有大量空白的示例字符串: s = " " * 100 + 'a' + " " * 100 s.strip()和s.strip(“”)的计时分别为: %timeit s.strip() The slowest run took 32.74 times longer than the fa
str.strip()
,该调用默认使用空白分隔符,也可以显式地为参数提供str.strip(“”)
但是,为什么这些功能在计时时表现如此不同
使用带有大量空白的示例字符串:
s = " " * 100 + 'a' + " " * 100
s.strip()
和s.strip(“”)
的计时分别为:
%timeit s.strip()
The slowest run took 32.74 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 396 ns per loop
%timeit s.strip(' ')
100000 loops, best of 3: 4.5 µs per loop
strip
需要396ns
而strip(“”)
需要4.5μs
,在相同的条件下,rsplit
和lsplit
也存在类似的情况。也
对python3.5.2
执行计时,在python2.7.1
上,差异不太明显。没有任何有用的指示,那么,为什么会发生这种情况 在tl中;时尚博士:
这是因为两种不同的情况下存在两种功能,如中所示do_strip
和\u pyunicodestrip
第一个执行速度比第二个快得多
函数用于不存在参数的常见情况str.strip()
,而(它包装\u PyUnicode\u XStrip
)用于调用str.strip(arg)
的情况,即提供参数
do_argstrip
只检查分隔符,如果它有效且不等于None
(在这种情况下,它调用do_strip
)它调用
do_strip
和pyunicodexstrip
遵循相同的逻辑,使用两个计数器,一个等于零,另一个等于字符串长度
使用两个while
循环,第一个计数器递增,直到达到不等于分隔符的值,第二个计数器递减,直到满足相同的条件
区别在于检查当前字符是否不等于分隔符的方式不同
对于do_strip
:
在最常见的情况下,要拆分的字符串中的字符可以用ascii
表示,这会带来额外的性能提升
while (i < len) {
Py_UCS1 ch = data[i];
if (!_Py_ascii_whitespace[ch])
break;
i++;
}
- 通过
Py_UCS4 ch=PyUnicode_读取(种类、数据、i)完成访问代码>
- 检查字符是否为空白是由宏完成的(该宏仅调用另一个宏:)
\u pyunicodestrip
:
在本例中,访问底层数据与前一例一样,是通过PyUnicode_Read
完成的;另一方面,检查字符是否是空白(或者实际上是我们提供的任何字符)要稍微复杂一些
while (i < len) {
Py_UCS4 ch = PyUnicode_READ(kind, data, i);
if (!BLOOM(sepmask, ch))
break;
if (PyUnicode_FindChar(sepobj, ch, 0, seplen, 1) < 0)
break;
i++;
}
while(i
使用,虽然效率很高,但与阵列访问相比要复杂得多,速度也慢得多。对于字符串中的每个字符,将调用它以查看该字符是否包含在我们提供的分隔符中。随着字符串长度的增加,不断调用此函数所带来的开销也会增加
对于那些感兴趣的人来说,PyUnicode\u FindChar
经过多次检查后,最终将在stringlib
内部调用,在分隔符长度为<10
的情况下,它将循环,直到找到字符为止
除此之外,考虑为了到达这里需要调用的附加函数。
至于
lstrip
和rstrip
,情况类似。要执行条带化的模式存在的标志,即:rstrip的RIGHTSTRIP
,lstrip的LEFTSTRIP
,以及strip的和BOTHSTRIP
。do_strip
和\u PyUnicode_XStrip
中的逻辑是根据标志有条件地执行的。由于@Jims answer中解释的原因,在字节
对象中发现了相同的行为:
b = bytes(" " * 100 + "a" + " " * 100, encoding='ascii')
b.strip() # takes 427ns
b.strip(b' ') # takes 1.2μs
对于bytearray
对象,这种情况不会发生,在这种情况下执行split
的函数对于这两种情况都是类似的
此外,在python2
中,根据我的计时,同样的情况适用于较小的范围
b = bytes(" " * 100 + "a" + " " * 100, encoding='ascii')
b.strip() # takes 427ns
b.strip(b' ') # takes 1.2μs