我有一個長字串存盤在 Rust 的一個變數中。drain我經常用一個方法從它的前面洗掉一些字符并使用從它回傳的值:
my_str.drain(0..i).collect::<String>();
問題是,從這個字串中提取資料在程式中經常發生,這會大大降低它的速度(它需要大約 99.6% 的運行時間)。這是一個非常昂貴的操作,因為每次都必須將整個字串移到記憶體中。
我根本不從繩子的末端排出(這應該快得多),只是從前面排出。
我怎樣才能使它更有效率?是否有一些替代方案String,使用不同的記憶體布局,這對于這個用例會更好?
uj5u.com熱心網友回復:
如果由于生命周期而不能使用切片,則可以使用提供共享所有權的型別,例如SharedString共享字串板條箱或位元組實用程式Str板條箱。前者看起來功能更齊全,但都提供了可以在 O(1) 中從字串中獲取前綴的方法,因為原始資料永遠不會移動。
uj5u.com熱心網友回復:
正如@Jmb 所述,保持原始字串完好無損并使用切片無疑是一個巨大的勝利。
從問題中我不知道這些字串的背景關系和用法,但是這個快速而骯臟的基準測驗顯示了性能上的顯著差異。
這個基準測驗是有缺陷的,因為clone()每次重復都有一個無用的,沒有熱身,沒有結果的黑匣子,沒有統計資料……但它只是給出了一個想法。
use std::time::Instant;
fn with_drain(mut my_str: String) -> usize {
let mut total = 0;
'work: loop {
for &i in [1, 2, 3, 4, 5].iter().cycle() {
if my_str.len() < i {
break 'work;
}
let s = my_str.drain(0..i).collect::<String>();
total = s.len();
}
}
total
}
fn with_slice(my_str: String) -> usize {
let mut total = 0;
let mut pos = 0;
'work: loop {
for &i in [1, 2, 3, 4, 5].iter().cycle() {
let next_pos = pos i;
if my_str.len() <= next_pos {
break 'work;
}
let s = &my_str[pos..next_pos];
pos = next_pos;
total = s.len();
}
}
total
}
fn main() {
let my_str="I have a long string stored in a variable in Rust.
I often remove some characters from its front with a drain method and use the value returned from it:
my_str.drain(0..i).collect::<String>();
The problem is, that draining from this string is done really often in the program and it's slowing it down a lot (it takes ~99.6% of runtime). This is a very expensive operation, since every time, the entire string has to be moved left in the memory.
I do not drain from the end of the string at all (which should be much faster), just from the front.
How can I make this more efficient? Is there some alternative to String, that uses a different memory layout, which would be better for this use case?
".to_owned();
let repeat = 1_000_000;
let instant = Instant::now();
for _ in 0..repeat {
let _ = with_drain(my_str.clone());
}
let drain_duration = instant.elapsed();
let instant = Instant::now();
for _ in 0..repeat {
let _ = with_slice(my_str.clone());
}
let slice_duration = instant.elapsed();
println!("{:?} {:?}", drain_duration, slice_duration);
}
/*
$ cargo run --release
Finished release [optimized] target(s) in 0.00s
Running `target/release/prog`
5.017018957s 310.466253ms
*/
uj5u.com熱心網友回復:
正如@SUTerliakov 所提議的,VecDeque<char>在這種情況下使用比String使用pop_front方法或drain方法(當然是從前面排出時)更有效
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/537624.html
標籤:细绳表现记忆锈
