使用str.strip可以通过两种方式在空白上进行拆分。您可以发出没有参数的调用,str.strip() (默认使用空白分隔符),也可以使用str.strip(' ')显式地自己提供参数。
但是,为什么这些函数在计时时表现得如此不同呢?
使用带有有意空白的示例字符串:
s = " " * 100 + 'a' + " " * 100s.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 loopstrip采用396ns,而strip(' ')采用4.5 μs,在相同的条件下,rstrip和lstrip也会出现类似的场景。还有, seem do be affected too。
时间是为Python 3.5.2执行的,而在Python 2.7.1上则没有太大的差别。str.strip没有指出任何有用的东西,所以,为什么会发生这种情况?
发布于 2016-07-09 19:38:30
以一种流行的方式:
这是因为对于这两种不同的情况,存在两个函数,在unicode_strip中可以看到;do_strip和_PyUnicodeXStrip --第一个函数的执行速度比第二个函数快得多。
函数do_strip用于不存在参数的公共情况str.strip()和调用str.strip(arg)的情况下的do_argstrip (包装_PyUnicode_XStrip),即提供参数。
do_argstrip只检查分隔符,如果它有效且不等于None (在这种情况下它调用do_strip),则调用_PyUnicode_XStrip。
do_strip和_PyUnicode_XStrip都遵循相同的逻辑,使用两个计数器,一个等于零,另一个等于字符串的长度。
使用两个while循环,第一个计数器被递增,直到达到一个不等于分隔符的值,第二个计数器被递减,直到满足相同的条件。
区别在于检查当前字符是否等于分隔符的方式。
对于do_strip
在最常见的情况下,要拆分的字符串中的字符可以用ascii表示,这会带来额外的小性能提升。
while (i < len) {
Py_UCS1 ch = data[i];
if (!_Py_ascii_whitespace[ch])
break;
i++;
}Py_UCS1 ch = data[i];,可以快速访问数据中的当前字符_Py_ascii_whitespace[ch]的数组进行检查。因此,简而言之,它是相当有效的。
如果字符不在ascii范围内,差异并不那么大,但它们确实减缓了整个执行过程:
while (i < len) {
Py_UCS4 ch = PyUnicode_READ(kind, data, i);
if (!Py_UNICODE_ISSPACE(ch))
break;
i++;
}Py_UCS4 ch = PyUnicode_READ(kind, data, i);完成的Py_UNICODE_ISSPACE(ch)宏完成的(只需调用另一个宏:Py_ISSPACE)对于_PyUnicodeXStrip
在这种情况下,访问底层数据,就像在前面的例子中一样,是用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++;
}使用PyUnicode_FindChar,虽然效率很高,但比数组访问要复杂得多,速度也慢得多。对于字符串中的每个字符,将调用该字符以查看该字符是否包含在我们提供的分隔符中。随着字符串长度的增加,调用此函数所带来的开销也会增加。
对于那些感兴趣的人,PyUnicode_FindChar经过相当多的检查后,最终会在stringlib中调用find_char,在分隔符长度为< 10的情况下,将循环到找到字符为止。
除此之外,还需要考虑需要调用的附加函数才能到达这里。
至于lstrip和rstrip,情况也很相似。存在要执行的条带模式的标志,即:RIGHTSTRIP用于rstrip,LEFTSTRIP用于lstrip,BOTHSTRIP用于strip。do_strip和_PyUnicode_XStrip内部的逻辑是根据标志有条件地执行的。
发布于 2016-07-09 21:24:51
由于@Jims中解释的原因,在bytes对象中也可以找到相同的行为:
b = bytes(" " * 100 + "a" + " " * 100, encoding='ascii')
b.strip() # takes 427ns
b.strip(b' ') # takes 1.2μs对于bytearray对象,这种情况不会发生,在这种情况下,执行split的函数在这两种情况下都是相似的。
此外,根据我的时间表,在Python 2中,同样的情况在较小的程度上也适用。
https://stackoverflow.com/questions/38285654
复制相似问题