C桑(Cython)从入门到入土(2): np数组操作对比

2024-01-12 21:36

本文主要是介绍C桑(Cython)从入门到入土(2): np数组操作对比,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

C桑(Cython)从入门到入土

2. np数组操作对比

Node sc518 Copy has image data of type unsigned long long

实际上, 👆🏻这个错误是我探索Cython的缘起…

code1:

Form:

更现代的方法是使用内存视图而不是指针:

cdef np.uint32_t[:,:,::1] mv_buff = np.ascontiguousarray(im, dtype = np.uint32)

[:,;,::1] 语法告诉 Cython 内存视图在内存中是 3D 和 C 连续的。将类型定义为内存视图而不是 numpy 数组的优点是
它可以接受定义缓冲区接口的任何类型,例如内置数组模块或来自 PIL 成像库的对象。
Memoryviews 可以在不持有 GIL 的情况下传递,这对于并行代码很有用
要从内存视图获取指针,请获取第一个元素的地址:

cdef np.uint32_t* im_buff = &mv_buff[0,0,0]

这比 <np.uint32_t*>mv_buff.data 更好,因为它避免了强制转换,并且强制转换通常可以隐藏错误。

👇的内容是小度在这里插入图片描述的回答:

这段代码涉及到Cython中的内存视图和numpy数组的使用。Cython是一种用来编写C扩展的Python语言,它可以提高Python代码的执行效率。让我们逐步解释这段代码:

  1. cdef np.uint32_t[:,:,::1] mv_buff = np.ascontiguousarray(im, dtype = np.uint32):

    • cdef np.uint32_t[:,:,::1] mv_buff: 这定义了一个3D的内存视图mv_buff,其数据类型为np.uint32_t(无符号32位整数)。:表示这个维度是开放的,也就是说它的大小可以根据源数组im的大小来自动确定。
    • np.ascontiguousarray(im, dtype = np.uint32): 这个函数将输入的numpy数组im转换为连续的内存布局,并指定数据类型为np.uint32_t
  2. [:,;,::1] 语法告诉 Cython 内存视图在内存中是 3D 和 C 连续的。:

    • [:,;,::1]是Cython中的内存视图语法,它定义了数组的维度和连续性。这里它表示一个3D的数组,并且在内存中是C风格连续的(即行优先)。
  3. 将类型定义为内存视图而不是 numpy 数组的优点是:

    • 可以接受定义缓冲区接口的任何类型,例如内置数组模块或来自 PIL 成像库的对象。
    • Memoryviews 可以在不持有 GIL 的情况下传递,这对于并行代码很有用。
  4. 要从内存视图获取指针,请获取第一个元素的地址:

    • cdef np.uint32_t* im_buff = &mv_buff[0,0,0]: 这行代码获取了内存视图mv_buff中第一个元素的地址,并将其赋给指针im_buff。这意味着现在可以通过这个指针直接访问和修改mv_buff中的数据。

简而言之,这段代码的主要目的是将一个numpy数组转换为连续的内存布局(使用Cython的内存视图),并获取该内存视图的第一个元素的地址。这样做通常是为了提高数据访问的效率或与需要连续内存布局的C/C++代码进行交互。

code2

From

from cython.cimports.cython.view import array as cvarray
import numpy as np# Memoryview on a NumPy array
narr = np.arange(27, dtype=np.dtype("i")).reshape((3, 3, 3))
narr_view = cython.declare(cython.int[:, :, :], narr)# Memoryview on a C array
carr = cython.declare(cython.int[3][3][3])
carr_view = cython.declare(cython.int[:, :, :], carr)# Memoryview on a Cython array
cyarr = cvarray(shape=(3, 3, 3), itemsize=cython.sizeof(cython.int), format="i")
cyarr_view = cython.declare(cython.int[:, :, :], cyarr)# Show the sum of all the arrays before altering it
print(f"NumPy sum of the NumPy array before assignments: {narr.sum()}")# We can copy the values from one memoryview into another using a single
# statement, by either indexing with ... or (NumPy-style) with a colon.
carr_view[...] = narr_view
cyarr_view[:] = narr_view
# NumPy-style syntax for assigning a single value to all elements.
narr_view[:, :, :] = 3# Just to distinguish the arrays
carr_view[0, 0, 0] = 100
cyarr_view[0, 0, 0] = 1000# Assigning into the memoryview on the NumPy array alters the latter
print(f"NumPy sum of NumPy array after assignments: {narr.sum()}")# A function using a memoryview does not usually need the GIL
@cython.nogil
@cython.ccall
def sum3d(arr: cython.int[:, :, :]) -> cython.int:i: cython.size_tj: cython.size_tk: cython.size_tI: cython.size_tJ: cython.size_tK: cython.size_ttotal: cython.int = 0I = arr.shape[0]J = arr.shape[1]K = arr.shape[2]for i in range(I):for j in range(J):for k in range(K):total += arr[i, j, k]return total# A function accepting a memoryview knows how to use a NumPy array,
# a C array, a Cython array...
print(f"Memoryview sum of NumPy array is {sum3d(narr)}")
print(f"Memoryview sum of C array is {sum3d(carr)}")
print(f"Memoryview sum of Cython array is {sum3d(cyarr)}")
# ... and of course, a memoryview.
print(f"Memoryview sum of C memoryview is {sum3d(carr_view)}")
# 此代码应提供以下输出:NumPy sum of the NumPy array before assignments: 351
NumPy sum of NumPy array after assignments: 81
Memoryview sum of NumPy array is 81
Memoryview sum of C array is 451
Memoryview sum of Cython array is 1351
Memoryview sum of C memoryview is 451

👇的内容是小度在这里插入图片描述的回答:

这段代码主要是关于Cython的内存视图(memoryview)特性,以及如何使用Cython与NumPy、C数组和Cython数组进行交互。下面是对代码的详细解释:

  1. 导入相关模块:

    • from cython.cimports.cython.view import array as cvarray: 导入Cython的carray(C风格数组)作为cvarray。
    • import numpy as np: 导入NumPy库。
  2. 创建NumPy数组:

    • narr = np.arange(27, dtype=np.dtype("i")).reshape((3, 3, 3)): 创建一个形状为(3,3,3)的整数数组,并初始化其值。
  3. 声明Cython内存视图:

    • narr_view = cython.declare(cython.int[:, :, :], narr): 为NumPy数组创建一个Cython内存视图。
    • carr = cython.declare(cython.int[3][3][3]): 声明一个C风格的3x3x3整数数组。
    • cyarr = cvarray(shape=(3, 3, 3), itemsize=cython.sizeof(cython.int), format="i"): 创建一个Cython的carray。
  4. 显示数组和赋值:

    • print(f"NumPy sum of the NumPy array before assignments: {narr.sum()}"): 在赋值之前打印NumPy数组的总和。
    • carr_view[...] = narr_viewcyarr_view[:] = narr_view: 将NumPy数组的值复制到C风格数组和Cython数组中。
    • narr_view[:, :, :] = 3: 将NumPy数组的所有元素设置为3。
    • carr_view[0, 0, 0] = 100cyarr_view[0, 0, 0] = 1000: 分别设置C风格数组和Cython数组的特定元素值。
  5. 检查赋值后的总和:

    • print(f"NumPy sum of NumPy array after assignments: {narr.sum()}"): 在赋值之后打印NumPy数组的总和,由于所有元素都被设置为3,所以总和应为27。
  6. 定义一个使用内存视图的函数:

    • @cython.nogil@cython.ccall 是Cython的装饰器,它们允许函数在没有全局解释器锁(GIL)的情况下运行,并允许直接调用C函数。
    • sum3d 函数接受一个三维整数数组作为参数,并返回其所有元素的总和。
  7. 调用内存视图函数:
    使用先前定义的sum3d函数,分别对NumPy数组、C风格数组、Cython数组以及C风格的内存视图调用该函数,并打印结果。

总的来说,这段代码展示了如何使用Cython的内存视图来与NumPy、C风格数组和Cython数组进行交互,以及如何通过内存视图进行高效的数值计算。

小结

C桑 这种啰嗦的语言风格, 真是让Python🐶抓狂😖…

不过, 这种高效倒是真的…

我们现在比纯 Python 版本快 7558 倍,比 NumPy 快 11.1 倍!
以上
未完待续

这篇关于C桑(Cython)从入门到入土(2): np数组操作对比的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型的操作流程

《0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeekR1模型的操作流程》DeepSeekR1模型凭借其强大的自然语言处理能力,在未来具有广阔的应用前景,有望在多个领域发... 目录0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型,3步搞定一个应

轻松上手MYSQL之JSON函数实现高效数据查询与操作

《轻松上手MYSQL之JSON函数实现高效数据查询与操作》:本文主要介绍轻松上手MYSQL之JSON函数实现高效数据查询与操作的相关资料,MySQL提供了多个JSON函数,用于处理和查询JSON数... 目录一、jsON_EXTRACT 提取指定数据二、JSON_UNQUOTE 取消双引号三、JSON_KE

C++实现封装的顺序表的操作与实践

《C++实现封装的顺序表的操作与实践》在程序设计中,顺序表是一种常见的线性数据结构,通常用于存储具有固定顺序的元素,与链表不同,顺序表中的元素是连续存储的,因此访问速度较快,但插入和删除操作的效率可能... 目录一、顺序表的基本概念二、顺序表类的设计1. 顺序表类的成员变量2. 构造函数和析构函数三、顺序表

使用C++实现单链表的操作与实践

《使用C++实现单链表的操作与实践》在程序设计中,链表是一种常见的数据结构,特别是在动态数据管理、频繁插入和删除元素的场景中,链表相比于数组,具有更高的灵活性和高效性,尤其是在需要频繁修改数据结构的应... 目录一、单链表的基本概念二、单链表类的设计1. 节点的定义2. 链表的类定义三、单链表的操作实现四、

Python利用自带模块实现屏幕像素高效操作

《Python利用自带模块实现屏幕像素高效操作》这篇文章主要为大家详细介绍了Python如何利用自带模块实现屏幕像素高效操作,文中的示例代码讲解详,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、获取屏幕放缩比例2、获取屏幕指定坐标处像素颜色3、一个简单的使用案例4、总结1、获取屏幕放缩比例from

通过prometheus监控Tomcat运行状态的操作流程

《通过prometheus监控Tomcat运行状态的操作流程》文章介绍了如何安装和配置Tomcat,并使用Prometheus和TomcatExporter来监控Tomcat的运行状态,文章详细讲解了... 目录Tomcat安装配置以及prometheus监控Tomcat一. 安装并配置tomcat1、安装