1

所以,我正在尝试对哈希进行详尽的搜索。哈希本身在这里并不重要。由于我想使用 CPU 的所有处理能力,因此我使用 Rayon 来获取线程池和大量任务。搜索算法如下:

let (tx, rx) = mpsc::channel();

let original_hash = String::from(original_hash);

rayon::spawn(move || {
    let mut i = 0;
    let mut iter = SenhaIterator::from(initial_pwd);
    while i < max_iteracoes {
        let pwd = iter.next().unwrap();

        let clone_tx = tx.clone();
        rayon::spawn(move || {
            let hash = calcula_hash(&pwd);
            clone_tx.send((pwd, hash)).unwrap();
        });

        i += 1;
    }
});

let mut last_pwd = None;
let bar = ProgressBar::new(max_iteracoes as u64);

while let Ok((pwd, hash)) = rx.recv() {
    last_pwd = Some(pwd);
    if hash == original_hash {
        bar.finish();
        return last_pwd.map_or(ResultadoSenha::SenhaNaoEncontrada(None), |s| {
            ResultadoSenha::SenhaEncontrada(s)
        });
    }
    bar.inc(1);
}
bar.finish();
ResultadoSenha::SenhaNaoEncontrada(last_pwd)

只是一个高级解释:随着任务完成他们的工作,他们将一对(密码,哈希)发送到主线程,主线程会将哈希与原始哈希(我试图为其查找密码的那个)进行比较)。如果它们匹配,很好,我返回 main 并返回一个表示成功的枚举值,以及产生原始哈希的密码。在所有迭代结束后,我将返回 main 并返回一个枚举值,该值指示未找到哈希,但使用最后一个密码,因此我可以在以后的某个运行中从这一点重试。

我正在尝试使用Indicatif来显示进度条,这样我就可以瞥见进度。

但我的问题是该程序正在增加它的内存使用量而没有明确的原因。如果我让它运行 10 亿次迭代,它会慢慢添加内存,直到填满所有可用的系统内存。

但是当我评论该行时bar.inc(1);,程序的行为与预期一样,内存使用正常。

我用 Rayon 和 Indicatif 创建了一个测试程序,但没有哈希计算,它可以正常工作,没有内存错误行为。

这让我觉得我的代码中的内存管理有问题,但我看不到任何明显的东西。

4

1 回答 1

1

我找到了一个解决方案,但我仍然不确定为什么它解决了原来的问题。

我为解决它所做的是将进度代码传输到第一个 spawn 闭包。查看下面的第 6 行和第 19 行:

let (tx, rx) = mpsc::channel();

let original_hash = String::from(original_hash);

rayon::spawn(move || {
    let mut bar = ProgressBar::new(max_iteracoes as u64);
    let mut i = 0;
    let mut iter = SenhaIterator::from(initial_pwd);
    while i < max_iteracoes {
        let pwd = iter.next().unwrap();

        let clone_tx = tx.clone();
        rayon::spawn(move || {
            let hash = calcula_hash(&pwd);
            clone_tx.send((pwd, hash)).unwrap();
        });

        i += 1;
        bar.inc();
    }
    bar.finish();
});

let mut latest_pwd = None;

while let Ok((pwd, hash)) = rx.recv() {
    latest_pwd = Some(pwd);
    if hash == original_hash {
        return latest_pwd.map_or(PasswordOutcome::PasswordNotFound(None), |s| {
            PasswordOutcome::PasswordFound(s)
        })
    }
}
PasswordOutcome::PasswordNotFound(latest_pwd)

第一个 spawn 闭包的作用是获取下一个密码以尝试将其传递给工作任务,该工作任务计算相应的哈希并将对(密码,哈希)发送到主线程。主线程将等待来自 rx 通道的对,并与预期的哈希值进行比较。

我仍然缺少的是为什么跟踪外线程的进度会泄漏内存。我无法确定真正泄漏的是什么。但它现在正在工作,我对结果很满意。

于 2020-11-08T16:28:15.860 回答