为什么执行startwith
速度比切片慢?
In [1]: x = 'foobar'
In [2]: y = 'foo'
In [3]: %timeit x.startswith(y)
1000000 loops, best of 3: 321 ns per loop
In [4]: %timeit x[:3] == y
10000000 loops, best of 3: 164 ns per loop
令人惊讶的是,即使包括长度计算在内,切片仍然明显更快:
In [5]: %timeit x[:len(y)] == y
1000000 loops, best of 3: 251 ns per loop
注意:此行为的第一部分已在
Python的数据分析
(第3章)中进行了说明,但未提供任何解释。
。
如果有帮助:这是startswith
;的C代码。这是输出dis.dis
:
In [6]: import dis
In [7]: dis_it = lambda x: dis.dis(compile(x, '<none>', 'eval'))
In [8]: dis_it('x[:3]==y')
1 0 LOAD_NAME 0 (x)
3 LOAD_CONST 0 (3)
6 SLICE+2
7 LOAD_NAME 1 (y)
10 COMPARE_OP 2 (==)
13 RETURN_VALUE
In [9]: dis_it('x.startswith(y)')
1 0 LOAD_NAME 0 (x)
3 LOAD_ATTR 1 (startswith)
6 LOAD_NAME 2 (y)
9 CALL_FUNCTION 1
12 RETURN_VALUE
__可以通过考虑.
操作员完成工作所需的时间来解释 某些 性能差异:
>>> x = 'foobar'
>>> y = 'foo'
>>> sw = x.startswith
>>> %timeit x.startswith(y)
1000000 loops, best of 3: 316 ns per loop
>>> %timeit sw(y)
1000000 loops, best of 3: 267 ns per loop
>>> %timeit x[:3] == y
10000000 loops, best of 3: 151 ns per loop
差的另一部分可以通过以下事实来解释startswith
是一个 函数 ,和甚至无操作html" target="_blank">函数调用需要一点时间:
>>> def f():
... pass
...
>>> %timeit f()
10000000 loops, best of 3: 105 ns per loop
这不能 完全 解释差异,因为使用切片的版本会len
调用函数,并且速度仍然更快(与sw(y)
267 ns相比):
>>> %timeit x[:len(y)] == y
1000000 loops, best of 3: 213 ns per loop
我唯一的猜测是,Python可能会针对内置函数优化查找时间,或者对len
调用进行了大幅优化(这可能是事实)。可以使用自定义len
功能进行测试。也许这是LastCoder识别出的差异所在。
startswith
比切片更复杂…
2924 result = _string_tailmatch(self,
2925 PyTuple_GET_ITEM(subobj, i),
2926 start, end, -1);
在干草堆开始时,这不是一个简单的字符比较循环。我们正在寻找一个遍历向量/元组(subobj)并_string_tailmatch在其上调用另一个函数()的for循环。多个函数调用在堆栈,参数完整性检查等方面都有开销。
startswith
是库函数,而切片似乎是内置在语言中的。
2919 if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end))
2920 return NULL;
问题内容: 我很好奇拆包切片并将其作为参数发送给可变参数函数。 假设我们有一个带有可变参数的函数: 如果我们不想传入一个接口,它就可以工作,那么我们是否拆包都没关系: 如果我们有一片片的话,那会很棘手。在这里,编译器不允许我们传递解压版本: 错误提示: 在解包参数中不能将sliceOfSlices(类型[] [] interface {})用作类型[] interface {} 我不知道为什么会这
问题内容: 考虑下面的go代码: : 我不明白的是,为什么taste_fruits的容量为3,直觉上我希望为2,因为这是切片的长度? 而且,如果tasty_fruits的容量为3,那么为什么: 造成: 问题答案: 这行: 创建一个 数组 ,而不是一个切片。即使您仅提供了3个元素,它也有4个元素。输出: 切片: 结果是: 长度:明显2.容量? 的 容量 是…的片的长度和超过所述切片中的[基本]阵列的
有人在IRC中提到它是切片问题。
问题内容: 许多Java书籍都将该语句描述为比该语句快。但是我没有找到任何地方为什么切换比if更快。 例 我有一种情况,我必须选择两项中的任何一项。我可以使用 要么 考虑item和BREAD是一个恒定的int值。 在上面的示例中,哪个操作更快,为什么? 问题答案: 因为有很多情况下,有一些特殊的字节码可以有效地评估switch语句。 如果使用IF语句实现,则将进行检查,跳转到下一个子句,进行检查,
问题内容: 为什么会发生以下现象: 可执行示例 问题答案: 构建一个空切片,就像一个空数组一样,它是一个有效且有用的对象(在所有语言中,而不仅仅是在Go中)。 空切片还仍然指向基础数组,位置和容量,有时可以扩展: 另一方面,长度为负的切片不一致。它没有任何意义,因此被禁止。
问题内容: 我想知道为什么你不能做: 我发现这将需要运行时在片上执行循环以转换每个元素,这将是非惯用的Go。这很有道理。 然而,这可能不会被刚刚走样编译器解决的,所以在内部它们是相同的,他们使用相同类型的头底下?我猜答案虽然不是我好奇为什么。 问题答案: 这个: 是类型转换。根据规范,转换具有特定的规则: 在以下任何一种情况下,可以将非恒定值转换为类型: 是分配给。 的类型,并且具有相同的基础类型