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

Rust Criterion基准测试如何传入未实现Copy trait的参数避免所有权错误

问题根因

你遇到的所有权错误本质是:c.bench_function 传入的闭包会被Criterion反复执行多次,外层定义的tokens在第一次被传入hash函数时所有权就被转移走,后续执行闭包时已经没有合法的tokens可以使用,因此编译器直接阻止了这种写法。

解决方案

方案1:调整被测函数签名(最优,无额外开销)

如果你的hash函数不需要消费传入的Vec,仅需要读取内部元素,直接将入参改为不可变借用的切片即可,这也是Rust中参数传递的最佳实践:
修改函数签名为:

pub fn hash(vector: &[&str]) -> u64

对应的基准测试代码调整为:

pub fn criterion_benchmark(c: &mut Criterion) {
    let s: String = String::from("Hello World!");
    let tokens: Vec<&str> = hashing::tokenize(&s);
    c.bench_function(
        "hash",
        |b| b.iter(|| {
            // 仅传入不可变借用,不会发生所有权转移
            hashing::hash(&tokens)
        }),
    );
}

该方案不会引入任何额外开销,基准测试结果完全准确。

方案2:使用iter_batched分离参数准备与测试执行(次优,结果准确)

如果你不能修改hash函数的签名,必须传入Vec的所有权,就使用Criterion提供的iter_batched方法,这个方法会把参数准备的耗时和被测函数的执行耗时分开统计,不会影响基准结果的准确性:

use criterion::BatchedSize;

pub fn criterion_benchmark(c: &mut Criterion) {
    let s: String = String::from("Hello World!");
    let tokens: Vec<&str> = hashing::tokenize(&s);
    c.bench_function(
        "hash",
        |b| b.iter_batched(
            // 每次执行测试前准备参数,这部分耗时不会被算进基准结果
            || tokens.clone(),
            // 实际执行被测函数,这部分耗时会被统计
            |local_tokens| hashing::hash(local_tokens),
            // 根据参数大小选择,小参数用SmallInput,大参数用LargeInput
            BatchedSize::SmallInput
        ),
    );
}

方案3:直接在iter闭包内克隆参数(不推荐,仅做临时验证用)

如果你只是临时测试且参数克隆开销极低,可以直接在iter的闭包内克隆参数,不过这种方法会把克隆的耗时算进被测函数的执行时间里,得到的基准结果会偏高:

pub fn criterion_benchmark(c: &mut Criterion) {
    let s: String = String::from("Hello World!");
    let tokens: Vec<&str> = hashing::tokenize(&s);
    c.bench_function(
        "hash",
        |b| b.iter(|| {
            hashing::hash(tokens.clone())
        }),
    );
}

内容的提问来源于stack exchange,提问作者bergwald

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 00:06:03