You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C代码转Zig与Rust的性能差异:Rust版本耗时过高问题排查

Rust代码性能落后C/Zig的问题分析

测试代码对比

C代码(耗时85秒)

unsigned int sorted_stepping(double seed, unsigned int* list,
                             unsigned int max_val, unsigned int list_size) {
    unsigned int seat_number = round(seed * (max_val - list_size));

    for (int i = 0; i < list_size; ++i) {
        if (list[i] > seat_number) {
            break;
        } else {
            seat_number++;
        }
    }

    return seat_number;
}

int main() {
    unsigned int max_val = 1000;
    unsigned int list[] = {1, 3, 4, 10, 15, 25, 100, 150, 214, 999, 1000};

    double seed = 0.0;
    unsigned int random_number;

    // calling the function 1,000,000,000 times
    for (long i = 0; i < 1000000000; ++i) {
        seed += 0.000000001;
        random_number = sorted_stepping(seed, list, max_val,
                                        sizeof(list) / sizeof(unsigned int));
    }

    fprintf(stdout, "Generated random number for seed %f is %d\n", seed, random_number);

    return 0;
}

Zig代码(耗时85秒)

const std = @import("std");

pub fn sorted_stepping(seed: f64, list: []const u32, max_val: u32) u32 {
    const temp: f64 = @floatFromInt(@as(usize, max_val) - list.len);
    var seat_number: u32 = @intFromFloat(@round(seed * temp));

    for (list) |list_item| {
        if (list_item > seat_number) {
            break;
        } else {
            seat_number = seat_number + 1;
        }
    }

    return seat_number;
}

pub fn main() void {
    const max_val = 1000;
    const list = [_]u32{ 1, 3, 4, 10, 15, 25, 100, 150, 214, 999, 1000 };

    var seed: f64 = 0.0;
    var random_number: u32 = 0;

    // calling the function 1,000,000,000 times
    for (0..1_000_000_000) |_| {
        seed += 0.000000001;
        random_number = sorted_stepping(seed, &list, max_val);
    }

    std.debug.print("Generated random number for seed {} is {}\n", .{ seed, random_number });
}

Rust代码(耗时250秒)

fn sorted_stepping(seed: f64, list: &[u64], max_val: u64, list_size: usize) -> u64 {
    let mut seat_number = (seed * (max_val - list_size as u64) as f64) as u64;

    for item in list {
        if item > &seat_number {
            break;
        } else {
            seat_number = seat_number + 1;
        }
    }

    seat_number
}

fn main() {
    let max_val: u64 = 1000;
    let list = [1, 3, 4, 10, 15, 25, 100, 150, 214, 999, 1000];

    let mut seed: f64 = 0.0;
    let mut random_number: u64 = 0;

    // calling the function 1,000,000,000 times
    let mut i: u32 = 0;
    while i < 1_000_000_000 {
        seed = seed + 0.000_000_001;
        random_number = sorted_stepping(seed, &list, max_val, list.len());
        i = i + 1;
    }

    println!("Generated random number for seed {0} is {1}", seed, random_number);
}

Rust代码的问题点

  1. 未使用release编译模式:这是核心原因——Rust默认编译为debug模式,会关闭所有优化并保留大量调试检查,性能比release模式差数倍。如果测试用的是cargo run默认命令,换成cargo run --release后性能会大幅接近C/Zig水平。
  2. 不必要的64位整数使用:C和Zig用32位无符号整数(unsigned int/u32),但Rust代码用了u64。64位整数运算在部分CPU上开销更高,频繁类型转换的损耗在10亿次调用下会被放大。
  3. 低效的循环写法:Rust用手动计数的while循环,而C/Zig用范围for循环。编译器对范围for循环的优化支持更好,更容易做循环展开、向量化等操作,手动while循环可能让编译器难以识别优化机会。
  4. 冗余参数与不必要的引用操作:sorted_stepping函数的list_size参数完全冗余,因为slice&[u64]本身包含长度,额外传参可能导致编译器做不必要的检查;循环里item > &seat_number可简化为*item > seat_number,减少不必要的引用比较操作。

为什么Zig更容易实现和C一致的性能

  1. 默认优化策略对齐C:Zig默认编译就是优化过的(类似C的-O2),不需要手动指定编译模式,新手不会因忘记开优化得到糟糕性能。
  2. 类型系统贴近C:Zig的整数类型、内存布局默认和C完全一致,类型转换规则直白,无隐式转换或额外语法糖,编译器更容易生成和C等价的机器码。
  3. 显式控制安全检查:Zig的安全检查是可选的,可通过编译选项关闭所有额外检查,完全复刻C的运行时行为;而Rust即使在release模式下,仍会保留部分内存安全检查(本例无影响),Zig的“显式控制”理念让开发者更易掌控性能。
  4. 函数调用与内联规则更宽松:Zig的小函数默认更容易被编译器内联,和C的内联行为一致;Rust虽支持内联,但需显式标注或依赖编译器自动判断,极致性能场景下Zig规则更贴近C。

内容的提问来源于stack exchange,提问作者Gokul Raj V

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 04:10:08