簡體   English   中英

生成字符串和識別子字符串非常慢

[英]Generating strings and identifying substrings is very slow

我想對Rust中的某些操作進行基准測試,但我似乎遇到了一些問題:

fn main(){

    let needle   = (0..100).map(|_| "b").collect::<String>();
    let haystack = (0..100_000).map(|_| "a").collect::<String>();

    println!("Data ready.");

    for _ in 0..1_000_000 {
        if haystack.contains( &needle ) {
            // Stuff...
        }
    }

}

上面需要很長時間才能完成,而Ruby中的相同操作在4.5秒左右完成:

needle   = 'b' * 100
haystack = 'a' * 100_000

puts 'Data ready.'

1_000_000.times do
    haystack.include? needle
end

我不禁想到我做了一些根本錯誤的事情。 在Rust中這樣做的正確方法是什么?

rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]

今天合並了這個問題的修復程序。 這意味着它應該是下一個夜晚的一部分,並且預計將在Rust 1.3中發布。 該修復程序恢復了Rust曾經擁有的雙向子字符串搜索實現,並將其調整為標准庫中的新Pattern API

雙向算法非常適合Rust的libcore,因為它是一個使用O(1)空間且不需要動態分配的線性時間子串搜索算法。

特定的實現包含一個簡單的添加,它會非常快速地拒絕這個問題中的特定查詢(不,它不是因為這個問題而編寫的,它也是舊代碼的一部分)。

在設置期間,搜索器計算針的指紋類型:對於針中的每個字節,取其低6位(數字0-63),然后設置u64可變byteset集中的相應位。

let byteset = needle.iter().fold(0, |a, &b| (1 << ((b & 0x3f) as usize)) | a);

由於針只包含'b',所以byteset的值只有第34位( 98 & 63 == 34 )。

現在我們可以測試任何字節是否可能是針的一部分。 如果未在byteset集中設置其相應位,則指針無法匹配。 在這種情況下,我們在大海撈針中測試的每個字節都是'a'( 97 & 63 == 33 ),並且它無法匹配。 因此算法將讀取單個字節,拒絕它,然后跳過針的長度。

fn byteset_contains(&self, byte: u8) -> bool {
    (self.byteset >> ((byte & 0x3f) as usize)) & 1 != 0
}

// Quickly skip by large portions unrelated to our substring
if !self.byteset_contains(haystack[self.position + needle.len() - 1]) {
    self.position += needle.len();
    continue 'search;
}

來自libcore/str/pattern.rs的rust-lang / rust

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM