Numba加速计算(CPU + GPU + prange)
文章目录
- 加速方法:Numba、CuPy、PyTorch、PyCUDA、Dask、Rapids
- 一、Numba简介
- 二、Numba类型:CPU + GPU
- 三、项目实战 —— 数组的每个元素加2
- 3.1、使用 python - range 循环计算 —— (时耗:137.37 秒)
- 3.2、使用 python - numpy 数组计算 —— (时耗:1.05 秒)
- 3.3、使用 numba - CPU 加速计算 —— (时耗:13.85 秒)
- 3.4、使用 numba - GPU 加速计算 —— (时耗:0.13 秒)
- 3.5、使用 numba.prange 并行循环计算

加速方法:Numba、CuPy、PyTorch、PyCUDA、Dask、Rapids
| 加速方法 | 简介 | 支持平台 | 适用范围 |
|---|---|---|---|
| Numba | 通过即时编译(JIT)来加速Python函数 | CPU + GPU | 数值计算(密集循环) |
| CuPy | NumPy的GPU加速库 | GPU | 数组操作和数学计算(大规模数据集) |
| PyTorch | 深度学习框架 | GPU | 张量操作和自动求导 |
| PyCUDA | 与CUDA交互的Python库 | GPU | 在Python中编写CUDA代码并在GPU上执行 |
| Dask | 并行计算库 | CPU + GPU | 并行操作(大规模数据集) |
| Rapids | 基于NVIDIA GPU加速的数据科学生态系统 | GPU | 提供数据处理和机器学习的库(如cuDF、cuML) |
一、Numba简介
Numba官网:专为 NumPy 科学计算而打造的,用于加速 Python 代码的即时编译器(Just-In-Time, JIT Compiler)。
由 Anaconda 公司主导开发
- 原理:使用行业标准
LLVM编译器库在运行时,将 Python 和 NumPy 代码的子集转换为快速的机器代码。- 速度:接近 C 或 FORTRAN 的速度
- 操作简单:只需将 Numba 装饰器之一应用到 Python 函数,Numba 将使用即时编译(JIT)编译为原生代码(机器代码),然后加速运行。
- 不需要替换 Python 解释器、运行单独的编译步骤,也不需要安装 C/C++ 编译器)
- 原生代码(Native code):直接在计算机硬件上执行的机器代码。
适用范围
- 只支持NumPy库(Numba 基于 NumPy 底层代码开发)
- 不支持其余的Python库(自定义-重开发:将函数分解为底层代码)
- (1)
NumPy数值计算(CPU):将 Python 函数即时编译为机器代码,用于加速数学运算等计算密集型任务(最初设计)。- (2)
NumPy数组操作(CPU):高效处理 NumPy 的数组操作和广播操作,且可以加速大型数组操作。- (3)
支持并行计算(CPU和GPU):使用 prange 来并行处理循环结构- (4)
支持GPU加速:将代码转移到 GPU 上以加速执行
二、Numba类型:CPU + GPU
Numba官网案例1:并行化测试(@jit、prange、dask)
Numba官网案例2:GPU加速
import numba # pip install numba
from numba import cuda, jit##############################################################
"""Numba装饰器:CPU加速"""
函数说明:@jit(nopython=True, parallel=True, target='cpu')
输入参数:(1)加速模式:nopython=True(默认)、forceobj=True 备注:Numba默认使用nopython编译函数。若无法完成编译,将使用对象模式(将导致性能损失)。(2)并行模式:parallel=True(默认)(3)指定平台:target='cpu'(默认)、target='gpu'> 多种不同的应用@jit() # 适用于科学计算、数值计算和密集计算。@jit(target='cpu') # CPU加速(与@jit()等效)@jit(target='cuda') # GPU加速(与@cuda.jit()等效)@jit(nopython=True) # 强制使用 nopython 模式,将函数尽可能编译成机器代码,如果无法完成编译则会引发错误(与@njit()等效)。@jit(forceobj=True) # 强制使用对象模式,而不是默认的 nopython 模式。适用于一些特殊情况,如涉及动态类型的代码。@jit(parallel=True) # 尝试并行化循环,充分利用多核处理器的性能(需将range转换为prange)。@njit() # 强制使用 nopython 模式,比@jit更快但更严格(只接受Numpy数据类型)。@vectorize # 适用于元素级别的向量化操作(单输入和单输出)、(输出数组的形状由输入数组的形状决定)@guvectorize # 适用于元素级别的向量化操作(多输入和输出数组)、(输出数组的形状可以指定)@stencil # 一种基于固定模板的局部计算。通过访问输入数组的邻域元素来计算输出数组的每个元素。
##############################################################
"""Numba装饰器:GPU加速""" @cuda.jit() # 用于在GPU上执行 CUDA 加速# @cuda.jit()与 @cuda.jit ———— 若不传递参数,两者是等效的。
# @cuda.jit 使用默认选项 @cuda.jit(),并且不需要传递任何参数。
# @cuda.jit() 显式调用 @cuda.jit 装饰器,并且可以传递一些选项参数。
三、项目实战 —— 数组的每个元素加2
3.1、使用 python - range 循环计算 —— (时耗:137.37 秒)
import numpy as npdef numpy_cpu_kernel(input_array):shape = input_array.shape # 获取数组形状result_array = np.zeros(shape) # 初始化一个全零数组,形状与输入数组相同# 循环遍历每个元素,将其加 2for z in range(shape[0]):for y in range(shape[1]):for x in range(shape[2]):result_array[z, y, x] = input_array[z, y, x] + 2return result_arrayif __name__ == "__main__":# 在主机上创建 3D 数组input_data = np.zeros((1024, 1024, int(1024 * 0.5)))import timestart_time = time.time()# 在主机上调用 NumPy 函数result_array_on_host = numpy_cpu_kernel(input_data)print(f"总共耗时: {time.time() - start_time:.2f} 秒")# 打印结果数组的形状和最大值print(result_array_on_host.shape)print(result_array_on_host.max())"""总共耗时: 137.37 秒"""
3.2、使用 python - numpy 数组计算 —— (时耗:1.05 秒)
import numpy as npdef numpy_cpu_kernel(input_array):return input_array + 2 # 将输入数组的每个元素加 2if __name__ == "__main__":# 在主机上创建 3D 数组input_data = np.zeros((1024, 1024, int(1024 * 0.5)))import timestart_time = time.time()# 在主机上调用 NumPy 函数result_array_on_host = numpy_cpu_kernel(input_data)print(f"总共耗时: {time.time() - start_time:.2f} 秒")# 打印结果数组的形状和最大值print(result_array_on_host.shape)print(result_array_on_host.max())"""总共耗时: 1.05 秒"""
3.3、使用 numba - CPU 加速计算 —— (时耗:13.85 秒)
from numba import jit
import numpy as np# 使用 Numba 的 jit 装饰器进行即时编译
@jit(nopython=True)
def my_cpu_kernel(input_array, output_array):# 使用三个嵌套循环遍历 3D 输入数组的每个元素for x in range(input_array.shape[2]):for z in range(input_array.shape[0]):for y in range(input_array.shape[1]):# 执行简单的操作:将输入数组的元素加 2,并将结果存储到输出数组中output_array[z, y, x] = input_array[z, y, x] + 2if __name__ == "__main__":# (1)在主机上创建输入数组input_data = np.zeros((1024, 1024, int(1024 * 0.5))) # 创建一个全零的3D数组result_array_on_host = np.zeros_like(input_data)# (2)在 CPU 上调用加速函数import timestart_time = time.time()my_cpu_kernel(input_data, result_array_on_host)print(f"总运行时间: {time.time() - start_time:.2f} 秒") # 打印运行时间# 打印输出数组的形状和最大值print(result_array_on_host.shape)print(result_array_on_host.max())"""总共耗时: 13.858259439468384"""
3.4、使用 numba - GPU 加速计算 —— (时耗:0.13 秒)
【深度学习环境配置】Anaconda +Pycharm + CUDA +cuDNN + Pytorch + Opencv(资源已上传)
在CUDA编程中
CPU和主存(RAM):称为主机(Host)GPU和显存(VRAM):称为设备(Device)
- CPU无法直接读取显存数据,GPU无法直接读取主存数据;
- 主机与设备必须通过总线(Bus)相互通讯;
RAM是CPU的主内存,显存是GPU的专用内存
GPU计算流程:
- (1)
cuda.to_device():将主机端的数据拷贝到设备端上,并在GPU上分配与主机上数据相同大小的内存。- (2)
cuda.device_array_like()或cuda.device_array():在GPU上分配用于输出数据的内存。- (3)
gpu[blocks_per_grid, threads_per_block]:在CPU上调用GPU函数,启动GPU多核并行计算(详细看1.2)。- (4)CPU与GPU异步计算;
- GPU函数的启动方式是异步的
异步计算:CPU不会等待GPU函数执行完毕才执行下一行代码。同步计算:在调用的GPU函数后面添加cuda.synchronize()—— 表示CPU需要等待GPU函数执行后再计算。- (5)
cuda.copy_to_host():将GPU设备端的计算结果拷贝回CPU主机端上。Python通过Numba实现GPU加速
- numba的GPU加速 —— 1天到1分钟的转变
- numba的GPU加速 —— 超过Numpy的速度有多难?
from numba import cuda
import numpy as np# 使用 Numba 的 CUDA 装饰器进行 GPU 加速
@cuda.jit
def my_cuda_kernel(input_array, output_array):x = cuda.grid(1) # 使用1维索引if x < input_array.shape[2]: # 检查索引是否在数组范围内for z in range(input_array.shape[0]):for y in range(input_array.shape[1]):# 执行简单的操作:将输入数组的元素加 2,并将结果存储到输出数组中output_array[z, y, x] = input_array[z, y, x] + 2if __name__ == "__main__":# (1)在主机上创建3D数组input_data = np.zeros((1024, 1024, int(1024 * 0.5)))# (2)拷贝数据 + 在GPU上分配内存device_input_array = cuda.to_device(input_data) # 将主机上的input_data复制到GPU上device_output_array = cuda.device_array_like(input_data) # 在GPU上开辟一个与 input_data 相同形状的数组用于存储计算结果。# (3)定义线程块的大小 + 线程块的数量threads_per_block = (16,)blocks_per_grid_x = (input_data.shape[2] + threads_per_block[0] - 1) // threads_per_block[0]blocks_per_grid = (blocks_per_grid_x,)# (4)调用CUDA核函数import timestart_time = time.time()my_cuda_kernel[blocks_per_grid, threads_per_block](device_input_array, device_output_array)print(f"总运行时间: {time.time() - start_time:.2f} 秒") # 打印运行时间# (5)将结果从GPU复制回主机result_array_on_host = device_output_array.copy_to_host() # 将计算结果从GPU复制回主机print(result_array_on_host.shape)print(result_array_on_host.max())"""总共耗时: 0.136000394821167"""
3.5、使用 numba.prange 并行循环计算
prange(parallel range):类似于Python标准库中的 range,但专用于并行化循环计算(引入额外的开销)。可以在多个处理器核心上同时执行循环,以提高密集型计算的性能。
适用范围:
大规模数据和密集型计算:只有在循环非常庞大时,才可以充分利用多核处理器,否则将导致耗时更长。独立迭代:每个迭代之间不存在依赖关系时,若后面的迭代依赖于前面迭代的计算结果(类似于递归函数),可能会导致耗时更长。NumPy数组:使用NumPy数组可以表现出更好的性能。
import random
import numba
import time###############################################
# numba加速 + 串行版本(Serial version)
###############################################
@numba.jit(nopython=True)
def monte_carlo_pi_serial(nsamples):acc = 0for i in range(nsamples):x = random.random()y = random.random()if (x ** 2 + y ** 2) < 1.0:acc += 1return 4.0 * acc / nsamples###############################################
# numba加速 + 并行版本(Parallel version)
###############################################
@numba.jit(nopython=True, parallel=True)
def monte_carlo_pi_parallel(nsamples):acc = 0for i in numba.prange(nsamples):x = random.random()y = random.random()if (x ** 2 + y ** 2) < 1.0:acc += 1return 4.0 * acc / nsamplesif __name__ == "__main__":start_time = time.time()monte_carlo_pi_serial(33000000) # 串行版本print(f"总共耗时: {time.time() - start_time:.2f} 秒")start_time = time.time()monte_carlo_pi_parallel(33000000) # 并行版本print(f"总共耗时: {time.time() - start_time:.2f} 秒")"""一万次循环:0.277700185775756840.42730212211608887三千万次循环:0.464895009994506840.4749984741210937510亿次循环:6.72973990440368651.1980292797088623100亿次循环:67.732758283615116.892062425613403"""
相关文章:
Numba加速计算(CPU + GPU + prange)
文章目录 加速方法:Numba、CuPy、PyTorch、PyCUDA、Dask、Rapids一、Numba简介二、Numba类型:CPU GPU三、项目实战 —— 数组的每个元素加23.1、使用 python - range 循环计算 —— (时耗:137.37 秒)3.2、使用 python…...
electron 两个渲染进程之间通信
一、使用主进程作为中介 使用主进程作为中介相对较为灵活,但可能会增加主进程的负担 1. 从一个渲染进程向主进程发送消息 在发送消息的渲染进程中,可以使用 ipcRenderer 模块向主进程发送消息。例如: const { ipcRenderer } require(&qu…...
配置ROS环境
1.检测环境变量 运行printenv | grep ROS命令,有如下返回值则表示环境变量配置正确: ROS_ROOT/opt/ros/kinetic/share/ros ROS_PACKAGE_PATH/opt/ros/kinetic/share ROS_MASTER_URIhttp://localhost:11311 ROSLISP_PACKAGE_DIRECTORIES ROS_DIST…...
力扣 128. 最长连续序列
题目描述 我的思路 我的思路比较暴力,就是首先将数组从小到大进行排序,然后再依次遍历判断序列是否连续并时时更新连续序列的最长长度。比如示例1:nums [100, 4, 200, 1, 3, 2],第一步先将数组进行排序得到sort_nums [1, 2, 3,…...
Stable Diffusion AI绘画工具的安装与配置(MAC用户)
AI绘画的热潮席卷了整个创意行业,Stable Diffusion作为其中的翘楚,让艺术创作变得前所未有的简单。然而,对于使用Mac电脑用户来说,安装和配置Stable Diffusion可能显得有些棘手。别担心,这份详细的教程将手把手教你如何…...
flowable源码解读——并行多实例节点任务是否是顺序生成
最近在项目开发中需要在多实例开始监听里修改一个全局的计数变量,不太确定并行多实例任务在底层引擎是顺序生成还是并行生成的,如果是顺序生成的则不影响,如果是并行生成 则修改一个全局的计数变量就会出现数据错误问题,查阅了flo…...
【机器学习】AGI的基本概念、技术挑战和应用前景
引言 AGI是指机器能够完成人类能够完成的任何智力任务的能力 文章目录 引言一、什么是AGI1.1 AGI,Artificial General Intelligence(通用人工智能)1.2 AGI的定义和标准1.3 AGI的发展 二、AGI的技术挑战2.1 理解人类智能2.2 认知复杂性2.3 自主…...
flink 使用RocksDB作为状态后端
RocksDB flink在生产环境中常用RocksDB作为状态后端 1、subtask在taskmanager中作为一个线程运行,如果设置了RocksDB状态后端,RocksDB也会启动一个独立的线程,供subtask来使用。 2、RocksDB是一个kv数据库,因此只能存储flink的键…...
【运维高级内容--MySQL】
目录 一、mysql安装 二、MySQL主从复制 一、mysql安装 yum install cmake gcc-c openssl-devel ncurses-devel.x86_64 rpcgen.x86_64 #安装依赖性 #在root路径下下载mysql-boost-5.7.44、libtirpc-devel-1.3.3-8.el9_4.x86_64.rpm安装包 yum install libtirpc-devel…...
【仿真与实物设计】基于51单片机设计的打地鼠游戏机——程序源码原理图proteus仿真图PCB设计文档演示视频元件清单等(文末工程资料下载)
基于51单片机设计的打地鼠游戏机 演示视频: 基于51单片机设计的打地鼠游戏机 功能描述:使用 51单片机为核心制作一个打地鼠游戏机。按下启动开关,8盏LED流水点亮并闪烁2次,随即开始播放游戏音乐,直到开始选择模式。选…...
iPhone设备使用技巧:忘记密码的情况下如何解除iOS 18/17屏幕时间
我们给了儿子一部新手机。在尝试擦除旧手机上的所有内容并恢复出厂设置时,它要求提供 4 位屏幕时间密码。我已经尝试了我们会使用的所有可能性,但无法弄清楚。我们如何绕过这个问题或将手机恢复出厂设置以便我们可以出售它? Apple 社区 对于…...
内网渗透的风行者—Yasso
Yasso : Yasso,让内网渗透变得简单而高效。- 精选真开源,释放新价值。 概览 Yasso是由sairson精心打造的内网渗透辅助工具集,它为网络安全专家和渗透测试人员提供了一个功能强大的工作平台。在面对错综复杂的网络环境时ÿ…...
Android13 app后台无法启动Abort background activity starts from
总纲 android13 rom 开发总纲说明 目录 1.前言 2.log分析 3.代码查找分析 4.修改方法 5.编译测试 6彩蛋 1.前言 Android13 用户app后台无法启动,提示Abort background activity starts from 10111 2.log分析 08-07 21:37:36.703: W/ActivityTaskManager(440): Back…...
Day45 | 99.岛屿数量 深搜 广搜 100.岛屿的最大面积
语言 Java 99.岛屿数量 深搜 广搜 99. 岛屿数量 题目 题目描述 给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可…...
css之grid布局(网格布局)
简述: 网格布局顾名思义就是将元素呈现为网状的整齐布局 简单使用: <div><div class"test"><div class"item">1</div><div class"item">2</div><div class"item">…...
数据可视化大屏模板-美化图表
Axure作为一款强大的原型设计软件,不仅擅长构建交互式界面,更在数据可视化方面展现出了非凡的创意与实用性。今天,就让我们一起探索Axure设计的几款精美数据可视化大屏模板,感受数据之美。 立体图表的视觉冲击力 Axure的数据可视…...
【与C++的邂逅】--- 类和对象(中)
Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏: 与C的邂逅 本篇博客我们将学习类和对象中,认识类的六个默认成员函数以及实现日期类。下图为本节思维导图。 🏠 类的6个默认成员函…...
[数据集][目标检测]瞳孔虹膜检测数据集VOC+YOLO格式8768张2类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):8768 标注数量(xml文件个数):8768 标注数量(txt文件个数):8768 标注…...
Day42 | 739. 每日温度 496.下一个更大元素 I 503.下一个更大元素II
语言 Java 739. 每日温度 每日温度 题目 给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该…...
运维大规模K8S集群注意事项
序言 闲来无事,一片混沌,想不清思不断,改变好像来自于各个方面,有的时候是内部的冲突,有的时候是外部的竞争,然而,大部分情况下,一旦错过,就已经没得选了。 尴尬的处境&a…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
