这几天经理让写个处理20G英语数据的程序,统计出这个大文件中出现的单词以及单词出现的频率,在测试的过程中总结了两类方法,在这里跟大家分享一下,如果遇到类似的情况,你也可以这么做。
我才用的第一种方法是文件映射,这个方法主要运用于脱壳在这里不介绍,这里主要介绍第二种方法,那就是文件流法。说实话,当初想采用这个方法的时候自己都感觉打醋,毕竟用文件流读取20G的数据再加上处理,会不会慢死呀。实践出真知,在文件连续的情况的下,采用I/O文件流的方法磁盘的读取速度可以到70M/s,而采用文件映射则只有30M/S。如果你的文件是连续的大文件,那么建议你使用文件流处理数据;如果文件是不连续的,那么建议使用文件映射。好了这里就介绍一下整个程序的构架。
由于文件是连续的,所以l/O的速度相当很快,文件的处理速度应该赶不上这个读取速度,所以这里使用了4个缓冲池来存放数据,同时开4个线程并发处理这4个缓冲池的数据,另外开一个单独的线程来监控这4个线程,如果某一个线程结束,那么就重新读取数据,并再次启动数据处理线程,总之这个线程就是个调度线程。单词的分割这里采用的是空格,所以左内存查找单词的时候就找空格就可以了,两个空格之间的部分就是单词(当然边界的单词可能被分割,这个单独处理)。
首先我们需要定义缓冲块的大小以及文件偏移存储。
我们的程序中主要分为5个线程,主线程以及4个辅助线程。主线程的作用就是读取数据并负责其余4个辅助线程的调度,这几个辅助线程的作用就是负责缓冲区数据的处理。这里我们使用了多线程同步制,对同步不懂的童鞋需要自己查资料啦。
在启动主线程之前我们需要进行一些列的初始化工作。
主线程启动后启动4个数据处理线程分别处理处理这4个缓冲区的数据,当其中的一个线程结束之后,我们可以得到当前结束的线程的素引号,这样我们的主线程就再次填充已经处理完的那个缓冲区,并重启已经结束的线程。这样在没有读完文件时不断的循环,知道文件读取完毕,并通知结束。下面是我们的数据处理线程:这里使我们处理数据的核心线程,里面使用hash_map来存储我们的单词。
本文看似纯粹的编程,但是这里跟大家分享的是一种编程的思路,在我们的编程中,大数据处理是一定会用到的,比如说IS O/GHO文件,这就需要进行大文件处理。当然,在大文件处理中我们不仅仅可以使用I/O流处理 :最多还有文件映射。这两种方法各有优势,对续存储的大文件来说,I/O的性能要远远高于文件映射,但如果遇到非常不连续的文件的话,还是有映射吧,因为这时候两个差不多了。
在附带的代码中已经实现了文件映射与缓冲区读取两种方法,读者可以自己参考阅读,如果没有这么大的文件,在工程中也添加了生成文件的函数。文章就写到这里,大家有不懂的可以来联系危险漫步。