让 Python 的属性查找具有 C 一级的性能

简介: 让 Python 的属性查找具有 C 一级的性能

前面我们介绍了静态类,静态类实例在属性查找方面比动态类要高效很多,因为静态类实例的属性是通过数组存储的,一个萝卜一个坑,访问的时候基于索引访问。但无论是静态类还是动态类,其实例在查找属性时,底层都会调用 PyObject_GetAttr 这个 C API。

那么问题来了,能不能再快一点呢?因为一旦涉及到 Python/C API,效率都是不高的,而 Python 的对象在底层都是一个 C 结构体,那么在查找属性的时候能不能直接访问 C 结构体的字段呢?不要再走 Python 的 C API 了。

我们举例说明:

cdef class Score:
    cdef public:
        int chinese, math, english
    def __init__(self, int chinese,
                 int math, int english):
        self.chinese = chinese
        self.math = math
        self.english = english
s = Score(90, 98, 92)
print(
    s.chinese, s.math, s.english
)  # 90 98 92

以上是一段 Cython 代码,如果换成功能相同的 C 代码的话:

#include <stdio.h>
typedef struct {
    int chinese;
    int math;
    int english;
} Score;
int main() {
    Score s = {90, 98, 92};
    printf("%d %d %d\n",
           s.chinese, s.math, s.english); // 90 98 92  
}

那么问题来了,我们能不能将 Cython 中的属性访问,转成 C 一级的属性访问呢?答案是可以的,下面来看一下具体的做法。

# 文件名:score.pyx
cdef class Score:
    cdef public:
        int chinese, math, english
    def __init__(self, int chinese,
                 int math, int english):
        self.chinese = chinese
        self.math = math
        self.english = english

我们需要先将 score.pyx 编译成扩展模块,编译方式很简单,这里不再赘述了。然后还要编写一个头文件 score.h:

#include <Python.h>
// 定义一个 C 结构体,模拟扩展类 Score
typedef struct {
    PyObject_HEAD
    int chinese;
    int math;
    int english;
} C_Score;

接下来再编写一个 Cython 源文件导入它:

# 文件名:cython_test.pyx
cdef extern from "score.h":
    ctypedef class score.Score [object C_Score]:
        cdef:
            int chinese
            int math
            int english
# 这里我们使用了 ctypedef class,可以简单认为导入了一个类
# 而 ctypedef class 紧跟的是 score.Score,编译器在看到之后
# 就知道要从 score 模块里导入类 Score
# 所以我们不需要 from score import Score,会自动导入
# 但是导入了还不算完,后面还跟了一个 C_Score
# C_Score 和 score.Score 里面的成员都是一样的
# 然后 Cython 编译器会生成 C 结构体字段的直接访问
# 而不会再走 Python 的 C API
def summer(Score s):
    # 进行类型声明的话,只需要使用 Score 即可
    # 并且这里的 Score 只能在 Cython 内部使用
    return s.chinese + s.math + s.english

然后进行编译,导入测试一下:

from score import Score
import cython_test
s = Score(99, 98, 97)
print(cython_test.summer(s))  # 294

结果没有任何问题,并且此时 Cython 是直接访问的结构体字段,而不是使用 __getattr__。

然后要说明的是,类的名字和 C 结构体的名字不要求相同,但是内部字段的名字应该是相同的。假设 C_Score 的字段如下

#include <Python.h>
// 定义一个 C 结构体,模拟扩展类 Score
typedef struct {
    PyObject_HEAD
    int a;
    int b;
    int c;
} C_Score;

那么声明的时候就应该这么做:

# 文件名:cython_test.pyx
cdef extern from "score.h":
    ctypedef class score.Score [object C_Score]:
        cdef:
            int chinese "a"
            int math "b"
            int english "c"

否则的话,在 C 结构体中就找不到对应的字段。当然啦,找不到的话会退化使用 __getattr__,不会报错。

此外该方法也适用于内置类型,不过用的不多,而且我们也很少使用 ctypedef class,因此本文的内容了解一下即可。

相关文章
|
23天前
|
测试技术 数据库 UED
Python 性能测试进阶之路:JMeter 与 Locust 的强强联合,解锁性能极限
【9月更文挑战第9天】在数字化时代,确保软件系统在高并发场景下的稳定性至关重要。Python 为此提供了丰富的性能测试工具,如 JMeter 和 Locust。JMeter 可模拟复杂请求场景,而 Locust 则能更灵活地模拟真实用户行为。结合两者优势,可全面评估系统性能并优化瓶颈。例如,在电商网站促销期间,通过 JMeter 模拟大量登录请求并用 Locust 模拟用户浏览和购物行为,可有效识别并解决性能问题,从而提升系统稳定性和用户体验。这种组合为性能测试开辟了新道路,助力应对复杂挑战。
51 2
|
2月前
|
测试技术 持续交付 Apache
性能怪兽来袭!Python+JMeter+Locust,让你的应用性能飙升🦖
【8月更文挑战第5天】随着互联网应用规模增长,性能测试至关重要。本文介绍如何利用Python结合Apache JMeter和Locust构建高效可定制的性能测试框架。JMeter广泛用于负载测试,通过模拟大量虚拟用户并发访问来评估性能。Locust基于Python,通过编写简单脚本模拟HTTP请求,特别适合Web应用测试,比JMeter更灵活易扩展。Python作为胶水语言简化测试脚本编写并流畅自动化流程。文章提供JMeter命令行测试和Locust脚本示例,并展示如何用Python自动化执行和整合测试结果,最终帮助应用在高负载下稳定运行。
72 1
|
7天前
|
测试技术 API Python
Python中requests、aiohttp、httpx性能对比
这篇文章对比了Python中三个流行的HTTP客户端库:requests、aiohttp和httpx,在发送HTTP请求时的性能,并提供了测试代码和结果,以帮助选择适合不同应用场景的库。
14 2
|
11天前
|
缓存 算法 数据处理
时间&空间复杂度,Python 算法的双重考验!如何优雅地平衡两者,打造极致性能?
在Python算法中,时间与空间复杂度的平衡至关重要。时间复杂度反映算法执行时间随输入规模的变化趋势,空间复杂度则关注额外存储空间的需求。优秀的算法需兼顾两者,如线性搜索时间复杂度为O(n),空间复杂度为O(1);二分查找在时间效率上显著提升至O(log n),空间复杂度保持为O(1);动态规划通过牺牲O(n)空间换取O(n)时间内的高效计算。实际应用中,需根据具体需求权衡,如实时数据处理重视时间效率,而嵌入式系统更关注空间节约。通过不断优化,我们能在Python中找到最佳平衡点,实现高性能程序。
30 3
|
15天前
|
并行计算 算法 Java
优化Python数据处理性能的策略
在数据密集型应用中,Python常因其解释性语言的特性而面临性能瓶颈。本文探讨了提升Python数据处理性能的几种策略,包括优化数据结构的选择、使用高效的库以及应用并行处理技术。通过具体示例和代码演示,读者将了解如何在实际开发中应用这些策略,从而显著提升数据处理速度。
|
15天前
|
存储 并行计算 大数据
优化Python数据处理性能的最佳实践
在数据科学和大数据时代,优化Python数据处理性能变得至关重要。通过探讨数据处理瓶颈、内存管理、并行计算以及高效库的使用,本篇文章旨在提供切实可行的最佳实践,以帮助开发者提升数据处理效率。
|
3天前
|
Python
Python中类属性与实例属性的区别
了解这些区别对于编写高效、易维护的Python代码至关重要。正确地使用类属性和实例属性不仅能帮助我们更好地组织代码,还能提高代码运行的效率。
6 0
|
5天前
|
Python
Python类中属性和方法区分3-8
Python类中属性和方法区分3-8
|
2月前
|
程序员 开发者 Python
Python动态属性与反射机制方式
通过反射和动态属性,Python程序员获得了巨大的权能,能在运行时访问、修改或为对象新增属性和方法,显著提高编程的智能化和适应性。内置的反射机制可能使开发者跨越编写代码时的限制,通过名称访问对象的特性、方法以及其他成员,为创建一个具有高度配置性、扩展性强大的应用程序打下基础。此外,利用getattr和setattr函数来获取和设定对象的属性,或是利用hasattr确认其是否存在某属性,甚至可以通过名字来动态地执行对象的函数。 总之,反射和动态属性对于Python的程序开发而言是重要的工具,它们不仅提供了编写效率高且灵活的代码的能力,还为构建可高度定制和扩展的应用程序提供了可能。对于熟练掌握这些
|
3月前
|
存储 缓存 算法
python性能问题(Performance Issues)
【7月更文挑战第19天】
51 5
python性能问题(Performance Issues)