我如何使用Rayon将大范围分成多个范围并让每个线程在一个块内找到?

时间:2018-05-10 11:20:32

标签: multithreading rust rayon

我正在制作一个程序,通过并行化来强制密码。目前,要破解的密码已经以纯文本形式提供,我只是试图强行破解它。

我有一个名为generate_char_array()的函数,它基于整数种子转换base并返回u8个字符片段来尝试检查。这首先是1个字符串的字母表,然后是2个等等。

let found_string_index = (0..1e12 as u64).into_par_iter().find_any(|i| {
    let mut array = [0u8; 20];
    let bytes = generate_char_array(*i, &mut array);
    return &password_bytes == &bytes;
});

使用找到的字符串索引(或种子整数),我可以生成找到的字符串。

问题在于Rayon对我进行并行化的方式是将任意大整数范围拆分为thread_count - 大切片(例如4个线程,0..2.5e11,2.5e11..5e11等)。这不好,因为范围的结尾是任意超大密码长度(10+,我不知道),而大多数密码(包括固定的" zzzzz"我倾向于尝试)更短,因此我得到的是第一个线程完成所有工作,其余的线程只是浪费时间测试太长的密码和同步;结果实际上比单线程性能慢。

我怎么能而是任意大范围(实际上并没有结束)分成块的范围并且每个线程都在块内找到?这将使不同线程中的工作人员真正有用。

2 个答案:

答案 0 :(得分:1)

这是我在评论中建议的版本。

主循环是并行的,并且仅在每次尝试的第一个字节上。对于每个第一个字节,请对剩余部分执行完整的强力搜索。

let matched_bytes = (0 .. 0xFFu8).into_par_iter().filter_map(|n| {
    let mut array = [0u8; 8];
    // the first digit is always the same in this run
    array[0] = n;
    // The highest byte is 0 because it's provided from the outer loop
    (0 ..= 0x0FFFFFFFFFFFFFFF as u64).into_iter().filter_map(|i| {
        // pass a slice so that the first byte is not affected
        generate_char_array(i, &mut array[1 .. 8]);
        if &password_bytes[..] == &array[0 .. password_bytes.len()] {
            Some(array.clone())
        } else {
            None
        }
    }).next()
}).find_any(|_| true);

println!("found = {:?}", matched_bytes);

另外,即使是强力方法,这仍然可能非常低效!

答案 1 :(得分:0)

如果Rayon按照您的描述拆分切片,则应用简单的数学运算来平衡密码长度:

let found_string_index = (0..max_val as u64).into_par_iter().find_any(|i| {
    let mut array = [0u8; 20];
    let v = i/span + (i%span) * num_cpu;

    let bytes = generate_char_array(*v, &mut array);
    return &password_bytes == &bytes;
});

span值取决于CPU的数量(Rayon使用的线程数),在您的情况下:

let num_cpu = 4;
let span = 2.5e11 as u64;
let max_val = span * num_cpu;

注意这种方法的性能高度依赖于Rayon如何在并行线程上执行序列拆分。验证它是否与您在问题中报告的一样有效。