【实用小功能10】python运行加速神器——numba(详细教学版)

2023-10-18 04:28

本文主要是介绍【实用小功能10】python运行加速神器——numba(详细教学版),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

      • 1. 为什么python这么慢?
        • 1.1 动态变量
        • 1.2. 解释性语言
      • 2. Numba的介绍和使用
        • 2.1 numba加速python小实例
        • 2.2 个人经验
        • 2.3 其他

1. 为什么python这么慢?

python比c++慢,尤其是存在循环的情况下,python和c+的区别主要有:

1.1 动态变量

c++中需要对变量类型有严格的定义,比如int或者float类型。但是python不需要,它去掉了变量申明和数据类型。python是一种动态类型语言,它会在做运算的时候根据变量的值自动推断出其类型,这种动态类型的特性使得python编写更加简单和灵活,但同时增加了一定的时间开销,反观c/c++在运算时则只是简单的内存读写和机器指令(加减乘除…),所以c/c++的速度比python快很多。

1.2. 解释性语言

c/c++是编译型语言,需要先将源代码编译成机器码,然后再运行程序。

python是解释性语言,它的源代码是直接由解释器解释执行的,这意味着在编写python代码时,不需要先将代码编译成可执行文件,而是可以直接运行代码。所以python的执行速度相较于c/c++会慢很多。

这个问题的一种解决方法就是即时编译JIT(Just-in-time compilation)JIT编译器会动态地将高级语言编写的代码转换为机器码,可以直接由计算机的处理器执行,这是在运行时完成的,也就是代码执行之前,因此称为“即时”。JIT针对特定的硬件和操作系统进行代码优化,可以使得python代码获得显著的性能提升。

2. Numba的介绍和使用

github主页:https://github.com/numba/numba

在线文档:https://numba.readthedocs.io/en/stable/index.html

可直接pip/conda下载库

conda install numba
pip install numba

numba非常适合于使用了numpy数组、函数和循环的代码,使用的方法就是装饰器,用它!用的好时间节省个几十倍。numba的可使用范围:

  • 操作系统:Windows (64 bit), OSX, Linux (64 bit).
  • 架构:x86, x86_64, ppc64le, armv8l (aarch64), M1/Arm64.
  • GPU:Nvidia CUDA.
  • CPython
  • NumPy版本:1.22~1.25
2.1 numba加速python小实例
  • 使用python计算一个矩阵的所有元素的和

  • 原始代码

def cal_sum(a): result = 0 for i in range(a.shape[0]): for j in range(a.shape[1]): result += a[i, j] return result start = time.perf_counter()
a = np.random.random((5000, 5000)) 
result = cal_sum(a)
end = time.perf_counter()
print("原始代码耗时:{}s".format((end - start)))#OUT:
#原始代码耗时:5.725140199996531s
  • 使用numba加速
import numba@numba.jit(nopython=True) 
def cal_sum(a): result = 0 for i in range(a.shape[0]): for j in range(a.shape[1]): result += a[i, j] return result start = time.perf_counter()
a = np.random.random((5000, 5000)) 
result = cal_sum(a)
end = time.perf_counter()
print("加速后耗时:{}s".format((end - start)))#OUT:
#加速后耗时:0.2892118000017945s

@jit(nopython=True)@njit是等同的,这个选项指示numba在编译时尽可能地避免使用python对象,将python代码转换为更快的机器码,而不是使用python解释器来执行代码。

  • 多次调用同一个使用了numba加速的函数

numba在第首次调用函数的时候进行了编译,但当编译发生后,numba会将该函数的机器码进行缓存,如果再次调用该函数,它会直接从缓存中加载,而不需要再次编译。简而言之,在一段代码中的使用了numba的函数,第二次、第三次…调用该函数运算都要比第一次耗时更少

x = np.arange(100).reshape(10, 10)@jit(nopython=True)
def go_fast(a):trace = 0.0for i in range(a.shape[0]):trace += np.tanh(a[i, i])return a + tracestart = time.perf_counter()
go_fast(x)
end = time.perf_counter()
print("首次调用耗时:{}s".format((end - start)))start = time.perf_counter()
go_fast(x)
end = time.perf_counter()
print("再次调用耗时:{}s".format((end - start)))#OUT:
#首次调用耗时:0.16958359999989625s
#再次调用耗时:4.7599998652003706e-05s
  • 使用并行加速【失败,原因还未知】

官方使用说明网址:numba-parallel

拿了官方的代码对比了下未使用并行和使用并行的,但是并行的反而更慢,没仔细细究缘由。

from numba import njit@njit()
def prange_test(A):s = 0for i in range(A.shape[0]):s += A[i]return sstart = time.perf_counter()
a = np.arange(1000)
result = prange_test(a)
end = time.perf_counter()
print("无并行耗时:{}s".format((end - start)))#OUT:
#无并行耗时:0.07213479999336414s
from numba import njit, prange@njit(parallel=True)
def prange_test(A):s = 0# Without "parallel=True" in the jit-decorator# the prange statement is equivalent to rangefor i in prange(A.shape[0]):s += A[i]return sstart = time.perf_counter()
a = np.arange(1000)
result = prange_test(a)
end = time.perf_counter()
print("并行耗时:{}s".format((end - start)))#OUT:
#并行耗时:0.36391139999614097s
2.2 个人经验

上面的函数比较简单,但是在实际使用中我们的函数可能复杂很多,简单地直接在函数上添加一个装饰器会出现各种报错,我们需要针对问题调整函数代码,大概陈列几个我遇到的问题及解决的方法。

  • 报错1
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Cannot infer the type of variable 'result', have imprecise type: list(undefined)<iv=None>. For Numba to be able to compile a list, the list must have a known and
precise type that can be inferred from the other variables. Whilst sometimes
the type of empty lists can be inferred, this is not always the case, see this
documentation for help:https://numba.pydata.org/numba-doc/latest/user/troubleshoot.html#my-code-has-an-untyped-list-problem

有些报错,会给个网址告诉你报错原因,点进去认真看下然后照着意思修改修改自己的代码就行了,但这个问题的解决方法如下:

@numba.jit(nopython=True) 
def test(): result, result1 = [], 0return result, result1test()# 改为
@numba.jit(nopython=True) 
def test(): result = []result1 = 0return result, result1test()
  • 报错2:
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Unknown attribute 'tolist' of type array(float32, 1d, C)...
Untyped global name 'input': Cannot determine Numba type of <class 'method'>

这样的问题是因为numba现在还有一些函数是不支持,比如上面python自带的input()函数和数组的tolist()函数,遇到这些问题的时候解决方法就是使用同样功能的且numba支持的函数or自己重写一个函数。

  • 报错3
def test_func():return True@jit(nopython=True)
def test(): flag = test_func()test()
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Untyped global name 'test_func': Cannot determine Numba type of <class 'function'>

这个问题是numba不支持函数中嵌套自己的函数,解决方法就是把调用的函数合并到一个函数中。

  • 报错4

会有一些与list列表相关的报错,numba貌似很不支持列表操作,尤其是嵌套列表类似[[[1,2],[2,3]],[[2,2],[8,3]]],解决方法是将这种列表改为数组进行操作。

2.3 其他

numba还提供了很多其他加速方法(我还没试):

  • 想节省编译时间,numba提供了提前编译模式:Ahead-of-Time compilation
  • 使用GPU:cuda-index

参考:Python 提速大杀器之 numba 篇

这篇关于【实用小功能10】python运行加速神器——numba(详细教学版)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/230158

相关文章

Python将博客内容html导出为Markdown格式

《Python将博客内容html导出为Markdown格式》Python将博客内容html导出为Markdown格式,通过博客url地址抓取文章,分析并提取出文章标题和内容,将内容构建成html,再转... 目录一、为什么要搞?二、准备如何搞?三、说搞咱就搞!抓取文章提取内容构建html转存markdown

Python获取中国节假日数据记录入JSON文件

《Python获取中国节假日数据记录入JSON文件》项目系统内置的日历应用为了提升用户体验,特别设置了在调休日期显示“休”的UI图标功能,那么问题是这些调休数据从哪里来呢?我尝试一种更为智能的方法:P... 目录节假日数据获取存入jsON文件节假日数据读取封装完整代码项目系统内置的日历应用为了提升用户体验,

将Mybatis升级为Mybatis-Plus的详细过程

《将Mybatis升级为Mybatis-Plus的详细过程》本文详细介绍了在若依管理系统(v3.8.8)中将MyBatis升级为MyBatis-Plus的过程,旨在提升开发效率,通过本文,开发者可实现... 目录说明流程增加依赖修改配置文件注释掉MyBATisConfig里面的Bean代码生成使用IDEA生

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

Python Websockets库的使用指南

《PythonWebsockets库的使用指南》pythonwebsockets库是一个用于创建WebSocket服务器和客户端的Python库,它提供了一种简单的方式来实现实时通信,支持异步和同步... 目录一、WebSocket 简介二、python 的 websockets 库安装三、完整代码示例1.

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1

Python使用自带的base64库进行base64编码和解码

《Python使用自带的base64库进行base64编码和解码》在Python中,处理数据的编码和解码是数据传输和存储中非常普遍的需求,其中,Base64是一种常用的编码方案,本文我将详细介绍如何使... 目录引言使用python的base64库进行编码和解码编码函数解码函数Base64编码的应用场景注意