F#与Rust性能对比测试疑问:编译优化及不稳定排序函数查询
性能测试对比与技术疑问
本次性能测试参考了一则对比Rust、Wasm、Python、Go性能的视频,原始Rust代码来自一个开源仓库,我在此基础上编写了F#代码进行性能对比。
测试代码
Rust代码
use rand::prelude::*; fn main() { let vec = make_random_vec(1_000_000, 100); for _ in 0..250 { let mut v = vec.clone(); // v.sort_unstable(); v.sort(); // 使用稳定排序,对应F#的稳定排序实现 } } pub fn make_random_vec(sz: usize, modulus: i64) -> Vec<i64> { let mut v: Vec<i64> = Vec::with_capacity(sz); for _ in 0..sz { let x: i64 = random(); v.push(x % modulus); } v }
F#代码
open System let rec cls (arr:int64 array) count = if count > 0 then let v1 = Array.copy arr let v2 = Array.sort v1 cls arr (count-1) else () let rnd = Random() let rndArray = Array.init 1000000 (fun _ -> int64 (rnd.Next(100))) cls rndArray 250 |> ignore
测试结果(Core i7 8代笔记本,WSL2环境)
- Rust(稳定排序):约17秒
- Rust(不稳定排序):约2.7秒
- F#:约11秒
技术疑问
- 是否因.NET编译器进行了优化,丢弃了未使用返回值的部分处理逻辑,导致F#代码运行更快?或是我的测试方案存在问题?
- F#是否提供可用于对比Rust不稳定排序的不稳定排序函数?
解答
问题1:关于编译器优化与测试方案的问题
首先要确认两个核心测试细节:
- 编译模式:必须确保Rust用Release模式编译(
cargo build --release),F#用Release模式构建(dotnet build -c Release)。如果Rust用Debug模式运行,性能会大幅下降,这是最容易犯的测试疏漏。 - 代码逻辑等价性:Rust的
v.sort()是原地排序,而F#的Array.sort会生成并返回新的排序后数组,两者内存操作逻辑完全不同:Rust每次循环克隆原Vec后原地修改;F#则是复制原数组,再生成新数组,内存分配和拷贝的开销差异会直接影响性能对比的公平性。
针对编译器优化的疑问:虽然代码中v2未被后续使用,但Array.sort包含大量计算逻辑,Release模式下.NET编译器不会轻易消除这类有明显计算开销的操作。可以修改代码验证:比如在排序后读取v2的首个元素并赋值给外部变量,强制排序操作执行,再重新测试看结果是否变化。
问题2:F#的不稳定排序函数
F#/.NET提供了对应的不稳定排序实现:
Array.sortInPlace:F#标准库函数,内部调用.NET System.Array.Sort,基于快速排序实现,属于不稳定排序,和Rust的sort_unstable逻辑对齐。- 直接调用
System.Array.Sort:.NET原生静态方法,原地修改数组,同样是不稳定排序。
如果要和Rust的sort_unstable做公平对比,需要将F#代码中的Array.sort替换为Array.sortInPlace(注意sortInPlace是原地修改数组,无需接收返回值,代码需调整为对v1直接调用)。
内容的提问来源于stack exchange,提问作者SR3142
相关产品推荐
相关产品推荐

