这是去年为了找工作,写的一个技术演示:以多线程暴力破解MD5密码为例,来演示一个完美的多线程编程方案。
在十年前,我写过一个单线程的暴力破解MD5密码程序(因为当时CPU还都是单核的),这次是把原来的程序多线程化了。
这个技术演示,写了多个不同实现方式的多个版本,一共花了2天时间(2014年5月3日-2014年5月4日)。
加密密码的暴力破解原理,不是本文重点,这里就不详细介绍了。
简单举例说明一下,对于尝试字符集为 a-z 26个小写字母,尝试长度为8位的话,就是把 a, b, ... z, aa, ab, ... zy, zz, aaa, ... aaaaaaaa, aaaaaaab, ... zzzzzzzy, zzzzzzzz,这26个小写字母,8位长度以内,所有的组合都尝试一遍,所以叫做暴力破解。尝试的结果,如果原加密密码在这个范围内,就必然找到。如果原加密密码不在这个范围内,那么该范围内的所有可能全部尝试完后,没有找到。尝试的方法就是对自己生成的每一个尝试串,进行和加密密码相同加密方式的加密,然后把加密后的尝试串,和加密密码进行比较,相同就说明找到了。
这种暴力破解,需要CPU进行超大量的计算。而需要CPU进行超大量计算的场景,是多线程技术的一个非常重要的应用场景。
我们以实例,来对暴力破解计算量形成一些概念:
以26个小写字母的各种组合进行尝试的话:
试完单独1位,需要对26种尝试串(a-z),进行计算和比较。
试完单独2位,需要对26+26*26=702种尝试串,进行计算和比较。
试完单独8位,需要对26的8次方+26的7次方+...+26=2171.80147158亿种尝试串,进行计算和比较。
使用四核 @3.4GHz 的CPU,以四线程(线程数超过CPU实际核数的话,速度不会提高)跑完2171.8亿种可能的话,估计要4个多小时。而以单线程跑完2171.8亿种可能的话,估计要16个小时以上。
大家有兴趣的话,可以下载本文附带的程序,自己尝试一下。
可以看到在需要CPU进行超大量计算的场景,多线程技术的使用是多么有意义。
多线程共同访问和处理同一数据源,一个非常重要的问题是,访问时需要互斥,否则的话,可能造成遗漏处理数据,或者重复处理数据。少量的重复处理数据是可以接受的,但是遗漏处理数据是不可接受的。为什么会出现重复和遗漏,我们这里不展开讲了。所以,多线程共同访问和处理同一数据源,访问时必需要互斥。
下面我们就来看一下,我所尝试过的几种实现方案。
多线程方案1:
尝试串只有1个。多个线程轮流取,然后再进行计算和比较。
这样的话,各个线程进行尝试的连续性好。但是,当一个线程在生成尝试串的过程中,另几个线程不能访问尝试串,线程需要阻塞等待。预计会经常出现这种情况,会很影响速度。
程序实现,
如果使用mutex来进行线程互斥的话,对速度的影响极为巨大,因为mutex部分代码的执行,四线程版甚至比单线程版还要慢很多很多。("ddzzzz"的md5的破解。四线程使用mutex互斥,118984ms。单线程大约13500ms。四线程比单线程还慢了8倍多)
如果使用InterlockedIncrement64,对程序的限制大。
多线程方案2:
把任务分成大致相等的n份(n为cpu的核数),然后创建n个线程,每个线程完成1份。
没有互斥的问题。
逻辑清晰性差,将来如果用于不同应用场景,代码比较难修改。
未作程序实现。
多线程方案3:
把任务分成固定的份数,然后创建n个线程(n为cpu的核数),每个线程做1份,做完之后,再去领1份,直到将所有的份数全部做完。
线程内,需要完成领一份的代码。领一份部分需要互斥。互斥部分出现的频率很少。
未作程序实现。
多线程方案4:
创建n个线程(n为cpu的核数)。
每个线程每次从总任务中,取一部分的任务进行处理,这部分任务处理完之后,再去取。直到将所有的任务全部处理完。好处是分配的比较均匀。连续性也较好。
程序实现,
"ddzzzz"的md5的破解,3线程4641ms。效果最好。
为什么说多线程方案4,是一种比较完美的多线程编程方案:
1,在一个对执行效率有很高要求的场景下,执行效率很高。
2,代码逻辑性非常好,适用性很广。很少的改动,就可以应用在很多的应用场景中。
本文所附带程序(http://pan.baidu.com/s/1i3ip4nb)说明:
MD5Calc.exe 图形界面,将指定的明文密码转换为MD5加密密码。
JiurlMd5CrackGui.exe 图形界面,多线程暴力破解演示程序,以本文多线程方案4实现。可以自行设定使用的线程数,默认线程数为CPU内核数减1。
TryCharset.txt 指定尝试字符集。
CryptedPassword.txt 指定要破解的密码。
临时主页:http://blog.sina.com.cn/ddqqppb
QQ高大上交流群:91877299