【问题标题】:Why is slicing much faster than "manual" assignment?为什么切片比“手动”分配快得多?
【发布时间】:2020-10-16 21:21:34
【问题描述】:

我正在研究一种数组旋转算法,您可以将数组向左旋转d 旋转步数。

我认为切片是一种高级抽象,实际上它比手动将数组中的每个值分配到旋转数组中的新位置要慢得多。

事实证明,切片的速度几乎快了 40 倍。这是为什么呢?

下面是对比代码:

def rot_left_manual(a, d):
    a_length = len(a)
    rot_arr = [0] * a_length
    for i in range(a_length):
        rot_arr[(i-d) % a_length] = a[i]
    return rot_arr


def rot_left_slice(a, d):
    i = d % len(a)
    b = a[i:]
    b += (a[:i])
    return b

我在 Jupyter 笔记本中使用 %timeit 来计时函数速度

【问题讨论】:

  • “我认为切片是一种高级抽象,实际上它比手动将数组中的每个值分配到旋转数组中的新位置要慢得多。”因为在 CPython 中,这种抽象在 C 中实现为优化的、已编译的代码,可与对象的内部一起使用。您的实现在解释器级别完成了大部分工作。
  • @juanpa.arrivillaga,这是有道理的,但我不明白一种语言如何在同一代码中使用另一种语言。
  • CPython 本身是用 C 编写的
  • @jeremyradcliff 计算机的底层硬件只能理解机器代码。 Python 以不同的速度运行,具体取决于代码如何从高级语言转换为低级机器语言。例如,PyPy 使用即时编译器,而标准实现 CPython 使用用 C 编写的解释器。由于编译产生的代码比动态解释更快,因此使用 PyPy 通常更快。使用低级语言优化模块是一种常见的做法。

标签: python arrays algorithm slice


【解决方案1】:

Python 的二进制操作相对昂贵。每次执行循环时查看rot_arr[(i-d) % a_length] = a[i]

  • 加载rot_arrida_lengtha
  • 调用i.__sub__()并创建中间对象
  • 调用intermed.__mod__()并创建中间对象
  • 调用rot_arr.__setitem__,递减并可能释放现有的obj

使用切片,几乎所有工作都在列表的切片方法(用 C 实现)中完成,该方法可以通过更少的计算优化大部分移动,并避免查找或创建所有这些 python 对象的费用。

【讨论】:

    猜你喜欢
    • 2012-09-14
    • 1970-01-01
    • 2019-12-07
    • 1970-01-01
    • 2014-04-21
    • 2015-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多