为何C/Python循环迭代耗时超预期?如何优化C代码适配处理器?
循环性能对比与C代码优化问题
各语言代码及运行耗时
Python代码及耗时
import os import time count = 0 number_of_itration = 100000000 begin = time.time() for i in range(number_of_itration): count += 1 end = time.time() print(f'Sum is {count}') print(f"Total runtime of the program is {end - begin} Seconds")
这段代码执行耗时12秒。
C代码及耗时
int main (int argc, char *argv[]) { if (InitCVIRTE (0, argv, 0) == 0) return -1; start_t = clock(); for(i=0; i< 100000000; i++) { count= count+1; } end_t = clock(); total_t = (double)(end_t - start_t) / CLOCKS_PER_SEC; printf("Total time taken by CPU: %f\n", total_t ); RunUserInterface (); return 0; }
这段代码耗时0.395秒。
LabVIEW代码及耗时
LabVIEW代码为一个1亿次递增的简单循环,运行仅耗时0.093秒。
问题分析与优化疑问
原本预期C代码运行更快,但实际耗时明显高于LabVIEW。使用的C IDE是National Instruments的LabWindows CVI,系统搭载Intel Core i7-10700处理器。需要明确两个问题:
- 为什么C代码性能不如LabVIEW?
- 如何针对当前处理器优化这段C代码?
问题原因及优化方案
性能差距的核心原因
- 编译器优化等级不足:LabVIEW对这类简单循环会自动启用激进优化(比如直接计算出最终结果,跳过循环执行),而LabWindows CVI默认可能只开启了低等级优化,没做循环展开、常量折叠等关键优化。
- 变量作用域不合理:代码里的
start_t、end_t、total_t、i、count都是全局变量,全局变量存放在内存中,每次读写都要访问内存;而LabVIEW的循环变量默认是寄存器级优化,读写速度远快于内存。 - 冗余代码干扰:代码中保留了
InitCVIRTE和RunUserInterface这类UI相关初始化/运行函数,即便计时在这些操作之后,也可能存在隐性的环境开销,而LabVIEW的测试代码是纯计算逻辑。
针对处理器的C代码优化方案
- 拉满编译器优化等级:在LabWindows CVI的编译设置中,将优化等级调到最高(比如O3级别),让编译器自动做循环展开、常量折叠、寄存器分配等优化。
- 将变量改为局部变量:把
count、i、start_t等变量都移到main函数内部定义,编译器会优先将局部变量分配到CPU寄存器,彻底消除内存访问的性能损耗。 - 用常量定义循环次数:把循环次数定义为宏常量,让编译器更容易识别并直接计算结果,跳过循环执行:
#define NUM_ITERATIONS 100000000 - 开启处理器指令集优化:在编译设置里开启对应处理器的指令集支持(比如AVX2,i7-10700原生支持),让编译器生成更高效的SIMD指令。
- 移除冗余代码:如果只是测试循环性能,直接去掉UI相关的
InitCVIRTE和RunUserInterface,写纯计算逻辑的C代码。
优化后的示例代码:
#include <stdio.h> #include <time.h> #define NUM_ITERATIONS 100000000 int main() { clock_t start_t, end_t; double total_t; int count = 0; int i; start_t = clock(); for(i = 0; i < NUM_ITERATIONS; i++) { count++; } end_t = clock(); total_t = (double)(end_t - start_t) / CLOCKS_PER_SEC; printf("Sum is %d\n", count); printf("Total time taken by CPU: %f\n", total_t); return 0; }
开启O3优化后,这段代码的耗时会大幅降低,甚至接近LabVIEW的水平——因为编译器会直接把循环优化成count = NUM_ITERATIONS,根本不会执行循环体。
内容的提问来源于stack exchange,提问作者Altroz
相关产品推荐
相关产品推荐

