神操作!两行代码,提速 13 倍!让 Python 飞一般的感觉!(2)

文章讲述了如何使用Numba加速Python中对Numpy数组进行递增排序的过程,对比了常规Python循环与Numba加速后的运行时间。同时提到了Numba的优缺点,包括即时编译带来的性能提升以及初次编译所需时间成本和与Python/Numpy原生实现的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Numpy ”爱莫能助“的时刻

假设你想要将一个非常大的数组转变为按递增顺序排序:很好理解,就是将元素按值的大小升序排列,如:

[1, 2, 1, 3, 3, 5, 4, 6] → [1, 2, 2, 3, 3, 5, 5, 6]

以下是一个简单的就地转换方式:

def monotonically_increasing(a):

max_value = 0

for i in range(len(a)):

if a[i] > max_value:

max_value = a[i]

a[i] = max_value

Numpy 运行很快,是因为它可以在不调用 python 自身解释器的前提下完成所有计算。但对于上面这个场景(python 中的循环),就会暴露出一个问题:我们会失去 Numpy 得天独厚的性能优势。

对一个含有一千万个元素的 Numpy 数组使用上面的函数进行转换,在我的电脑上需要运行 2.5 秒。那么,还可以优化得更快吗?

使用 Numba 提速

Numba 是一款为 python 打造的、专门针对 Numpy 数组循环计算场景的即时编译器。显然,这正是我们所需要的。让我们在原有函数的基础上添加两行代码试试:

from numba import njit

@njit

def monotonically_increasing(a):

max_value = 0

for i in range(len(a)):

if a[i] > max_value:

max_value = a[i]

a[i] = max_value

再次运行,发现仅需要 0.19 秒,在完全重用旧代码逻辑的前提下,感觉效果还不错。

实际上 Numpy 也有一个特殊的函数可以解决这种场景(但是会修改原有函数的代码逻辑):`numpy.maximum.accumulate`[1] 。通过使用它,函数的运行时长会缩短至 0.03 秒。

|

| Runtime |

| — | — |

| Python for loop | 2560ms |

| Numba for loop | 190ms |

| np.maximum.accumulate | 30ms |

Numba 简介

在 Numpy 或 Scipy 中找到目标函数,可以很快解决常见的计算问题。但是如果函数不存在呢?(比如刚刚的 numpy.maximum.accumulate)。这种情况下如果想加速代码运行。可能会选择其他低级的编程语言来实现扩展[2],但这也意味着切换编程语言,会让模块构建和系统总体变得更复杂。

使用 Numba 你可以做到:

  • 使用 python 和拥有更快编译速度的解释器运行同一份代码

  • 简单快速地迭代算法

Numba 首先会解析代码,然后根据数据的输入类型以即时的方式编译它们。例如,当输入是 u64 数组和浮点型数组时,分别得到的编译结果是不一样的。

Numba 还可以对非 CPU 的计算场景生效:比如你可以 在 GPU 上运行代码[3]。诚然,上文中的示例只是 Numba 的一个最小应用,官方文档[4]中还有很多特性可供选择。

Numba 的一些短板

需要一次代码编译耗时

当第一次调用 Numba 修饰的函数时,它需要花费一定的时间来生成对应的机器代码。比如,我们可以使用 IPython 的 %time 命令来计算运行一个 Numba 修饰的函数需要花费多长时间:

In [1]: from numba import njit

In [2]: @njit

…: def add(a, b): a + b

In [3]: %time add(1, 2)

CPU times: user 320 ms, sys: 117 ms, total: 437 ms

Wall time: 207 ms

In [4]: %time add(1, 2)

CPU times: user 17 µs, sys: 0 ns, total: 17 µs

Wall time: 24.3 µs

In [5]: %time add(1, 2)

CPU times: user 8 µs, sys: 2 µs, total: 10 µs

Wall time: 13.6 µs

可以看到,函数第一次调用后运行非常慢(注意单位时毫秒而不是微秒),这就是因为它需要时间来编译生成机器代码。不过函数后面的运行速度会显著提升。这种时间成本在输入数据的类型发生变化时会再次消耗,比如,我们将输入类型换为浮点数:

In [8]: %time add(1.5, 2.5)

CPU times: user 40.3 ms, sys: 1.14 ms, total: 41.5 ms

Wall time: 41 ms

In [9]: %time add(1.5, 2.5)

CPU times: user 16 µs, sys: 3 µs, total: 19 µs

Wall time: 26 µs

计算两数之和当然不需要启用 Numba,这里用这个案例是因为能够比较容易地看出编译所需的时间成本。

与 python 和 Numpy 的不同实现方式

Numba 在功能方面可以说是实现了 python 的一个子集,也可以说是实现了 Numpy API 的一个子集,这将会导致一些潜在的问题:

  • 会出现 python 和 Numpy 部分特性都不支持的情况

  • 由于 Numba 重新实现了 Numpy 的 API,在使用时可能会出现以下情况

  • 由于使用的不用的算法,两者的性能表现会有区别

  • 可能会由于 bug 导致结果不一致

  • 另外,当 Numba 编译失败时,其暴露的错误信息可能会很难理解

Numba 与其他选项的对比

  • 仅使用 Numpy 和 Scipy:可以让 python 代码运行时达到其他语言编译器的速度,但是对于某些循环计算的场景不生效
    自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Python开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以扫码获取!!!(备注Python)

ttps://img-blog.csdnimg.cn/img_convert/9f49b566129f47b8a67243c1008edf79.png)

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以扫码获取!!!(备注Python)

img
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值