Rust 函数与 Python 函数一样慢

Alb*_*ino 5 python rust

我正在尝试使用 Rust 来加速 Python 程序,而我对这门语言完全是初学者。n我编写了一个函数,用于计算较大字符串中每个可能的长度字符串的出现次数。例如,如果主字符串是"AAAAT"and n=3,则结果将是 hashmap {"AAA":2,"AAT":1}。我使用 pyo3 从 Python 调用 Rust 函数。Rust函数的代码是:

fn count_nmers(seq: &str, n: usize) -> PyResult<HashMap<&str,u64>> {
    let mut current_pos: usize = 0;
    let mut counts: HashMap<&str,u64> = HashMap::new();
    while current_pos+n <= seq.len() {
        //print!("{}\n", &seq[current_pos..current_pos+n]);
        match counts.get(&seq[current_pos..current_pos+n]) {
            Some(repeats) => counts.insert(&seq[current_pos..current_pos+n],repeats+1),
            None => counts.insert(&seq[current_pos..current_pos+n],1)
        };
        current_pos +=1;
    }
    //print!("{:?}",counts)
    Ok(counts)
}
Run Code Online (Sandbox Code Playgroud)

当我对n( n<10) 使用较小的值时,Rust 比 Python 快一个数量级,但随着 n 长度的增加,差距趋于零,两个函数的速度相同n=200。(见图) 不同 n 聚体长度的计数时间(Python 黑、铁锈红)

我一定是琴弦出了问题,但我找不到错误。


蟒蛇代码是:

def nmer_freq_table(sequence,nmer_length=6):
    nmer_dict=dict()
    for nmer in seq_win(sequence,window_size=nmer_length):
        if str(nmer) in nmer_dict.keys():
            nmer_dict[str(nmer)]=nmer_dict[str(nmer)]+1
        else:
            nmer_dict[str(nmer)]=1
    return nmer_dict

def seq_win(seq,window_size=2):
    length=len(seq)
    i=0
    while i+window_size <= length:
        yield seq[i:i+window_size]
        i+=1
Run Code Online (Sandbox Code Playgroud)

基准结果图

Evg*_*niy 2

您正在多次计算哈希函数,这对于较大的 n 值可能很重要。尝试使用输入函数而不是手动插入:

while current_pos+n <= seq.len() {
    let en = counts.entry(&seq[current_pos..current_pos+n]).or_default();
    *en += 1;
    current_pos +=1;
}
Run Code Online (Sandbox Code Playgroud)

完整代码在这里

接下来,确保您正在运行--release编译后的代码,例如cargo run --release.

这里讨论了还要记住的一件事,Rust 可能会针对您的情况使用非最佳哈希函数,您可以更改它。

最后,在大数据上,大部分时间都花在 HashMap/dict 内部,它们不是 python,而是编译代码。所以不要指望它能很好地扩展。