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
相关产品推荐
相关产品推荐

