让 for 和 while 循环具有 C 级别的性能

简介: 让 for 和 while 循环具有 C 级别的性能

Python 的 for 和 while 循环是灵活并且高级的,语法自然、读起来像伪代码。而 Cython 也支持 for 和 while,无需修改。但由于循环通常占据程序运行时的大部分时间,因此我们可以通过一些优化,确保 Cython 能够将 Python 循环转换为高效的 C 循环。

n = 100
for i in range(n):
    ...

上面是一个标准的 Python for 循环,如果这个 i 和 n 是静态类型,那么 Cython 就能生成更快的 C 代码。

cdef Py_ssize_t i, n = 100
for i in range(n):
    ...
# 这段代码和下面的C代码是等效的
"""
for (i=0; i<n; ++i) {
  /* ... */
}
"""

所以当通过 range 进行循环时,我们应该将 range 里面的参数以及循环变量换成 C 的整型。如果不显式地进行静态声明的话,Cython 就会采用最保守的策略:

cdef Py_ssize_t n = 100
for i in range(n):
    print(i + 2 ** 100)

在循环的时候,如果我们使用了变量 i,那么在和一个数字相加的时候,由于 Cython 无法确定是否会发生溢出,因此会保守的选择 Python 的整型。

如果我们能保证表达式中一定不会发生溢出,那么可以显式地将 i 也声明为 C 的整数类型。

当然不光是整型,其它的 Python 类型也可以提前声明,举个例子:

cdef list lst = [
    {"name": "satori", "age": 17},
    {"name": "koishi", "age": 16},
    {"name": "marisa", "age": 15},
]
# lst 里面都是字典,在遍历之前可以提前声明好
cdef dict item
for item in lst:
    print(f"{item['name']}, {item['age']}")
"""
satori, 17
koishi, 16
marisa, 15
"""
# 通过 cdef dict item 提前声明循环变量的类型
# 然后遍历以及操作的时候,速度会快很多
# 因为我们实现了基于类型的优化

以上是 for 循环,至于 while 循环也是同理,说白了还是规定好类型,实现基于类型的优化。

当然目前的优化还只是一部分,我们将在后续系列中了解优化循环体的更多信息,包括 Numpy 在 Cython 中的使用以及类型化内存视图。

循环的另一种方式

对于 Cython 而言,循环还有另一种方式,不过已经过时了,不建议使用,了解一下即可:

cdef int i
# 等价于 for i in range(0, 5)
# 不可以写成 for i from i >=0 and i < 5
for i from 0<= i < 5:  
    print(i)
"""
0
1
2
3
4
"""
# for i in range(0, 5, 2)
for i from 0 <= i < 5 by 2:  
    print(i)
"""
0
2
4
"""

这种循环在语法上看起来很酷,但是已经过时了,因此直接使用 range 即可。

相关文章
|
12月前
|
存储 编译器
深入解析i++和++i的区别及性能影响
在我们编写代码时,经常需要对变量进行自增操作。这种情况下,我们通常会用到两种常见的操作符:i++和++i。最近在阅读博客时,我偶然看到了有关i++和++i性能的讨论。之前我一直在使用它们,但从未从性能的角度考虑过,这让我突然产生了兴趣。尽管它们看起来相似,但它们之间存在微妙而重要的区别。在本文中,我们将详细解释i++和++i之间的区别,以及它们对代码性能的影响。
353 1
深入解析i++和++i的区别及性能影响
|
5月前
|
缓存 关系型数据库 MySQL
MySQL查询优化:提速查询效率的13大秘籍(合理使用索引合并、优化配置参数、使用分区优化性能、避免不必要的排序和group by操作)(下)
MySQL查询优化:提速查询效率的13大秘籍(合理使用索引合并、优化配置参数、使用分区优化性能、避免不必要的排序和group by操作)(下)
206 0
|
3月前
|
机器学习/深度学习 Java Serverless
函数计算产品使用问题之如何降低函数计算中的并发以解决流控错误
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
3月前
|
数据处理 数据库 索引
数据库索引策略如何影响数据的读取效率?
【7月更文挑战第3天】数据库索引策略如何影响数据的读取效率?
23 2
|
5月前
|
并行计算 索引 Python
讨论如何优化 DataFrame 操作,减少内存占用和提高执行速度
【5月更文挑战第19天】优化 DataFrame 操作涉及选择合适的数据类型、避免复制、使用向量化、高效迭代和设置索引。通过这些策略,如使用 `np.int8` 节省内存,直接修改列数据,利用 `itertuples`,设置分类数据类型,以及分块和并行计算,可以显著减少内存占用和提高执行速度,从而更好地处理大规模数据。实践中需结合具体情况综合运用,不断测试和优化。
167 2
|
11月前
|
Java
策略枚举:消除在项目里大批量使用if-else的优雅姿势
可以替换大量的if-else语句,且具备较好的可读性与扩展性,同时能显得轻量化,我比较推荐使用策略枚举来消除if-else。
96 0
|
监控 程序员 C++
[虚幻引擎] UE里面监控每帧循环里面 C++ 函数的性能,监控函数效率,函数执行时间。
在使用C++开发UE引擎,有时候需要监控函数的执行的执行效率,这个时候有两种方式可以使用。
182 0
|
SQL 存储 缓存
原来count(*)就是我们系统的接口性能变差100倍的真凶…
原来count(*)就是我们系统的接口性能变差100倍的真凶…
循环的差异性记录
循环的差异性记录循环的差异性记录