外部排序思想

如今我要进行排序,不过须要排序的数据很大,有1000G那么大,可是个人机器内存只有2G大小,因此每次只能把2G的数据从文件中传入内存,而后用一个“内部排序“算法在内存排好序后,再将这有序数据,载入一个2G大小的文件。而后再载入第二个2G数据。。。循环500遍以后,我如今获得500个文件,每一个文件2G,文件内部是有序的,而后我再比较这500个文件的第一个数,最小的确定就是这1000G数据的最小的。那么以后的过程你肯能想到了,就是不断将这500个2G 数据进行一个归并,最终就能获得这1000G的有序数据文件了。算法


举个例子,好比我要排序10个数,可是个人内存一次只能装下5个数,因此最初的10个数我只能放到文件里面(文件时外存,只要硬盘或磁盘够大,想多大就多大)。内部排序确定是得须要将数据载入内存中才能够进行的。数组


这10个数是[ 2 ,3,1,7,9 ,6, 8,4 ,5 ,0 ]。性能


第一次载入前五个数2,3,1,7,9.  排好序后是:1,2,3,7,9  而后导入一个只存五个数的文件中。优化


第二次载入后五个数6,8,4,5,0   排好序后是:0,4,5,6,8,而后倒入一个只存五个数的文件中。指针


以后在归并两个有序数列排序


第一个有序子数列的头位1,第二个为0,由于0而后在进行第二次比较,1和4进行比较。。。内存


重复进行最终获得一个有序数列的文件,里面存着,0,1,2,3,,,7,8,9资源


问题是:在这个过程当中,你能想到哪些优化?get


(擦,,,背景描述了半天,问题就一句话。。。当时我也很无语。。。) it


解答:


想了大概一分钟,除了增设一个缓冲buffer,加速从文件到内存的转储以外,我脑子里面一片空空。。。并且我想到的那个缓冲buffer所获得的回复是“假设这个优化系统已经帮你优化了” 。。。无语。。。


他看我眉头紧锁,而后给我作了一个提示:假设我如今把文件中的2G数据载入内存这个过程定义为”L”,把内存中的排序过程定义为”S” ,把排序好的 2G数据再转储到另外一个文件这个过程定义为”T”…


他还没说完,瞬间反应过来了!“用流水线并行实现“,而后我把流水线那个图画了出来,就是在计算机组成原理那本书中常常出现的“流水线图”。图画好后,他点点头,我也长嘘一口气。。。


而后他问我,用流水线技术以后为何会加速整个过程。


固然这个问题就很容易了,过去得把一组2G数据的三个过程所有处理完以后,才能进行下一个2G数据的处理,如今就能够三个过程并行着进行了。当时我也忘了,加速比怎么计算了,因此就没提这个东西。。。


他接着问,作了这个并行处理以后,会出现什么问题?


。。。MD,又是一个恶心问题,其实我清楚,问题不难,可是“找问题”好讨厌啊。。。


想了一下,我说,在“S”这个过程,也就是内部排序的这个环节最好不要用“快速排序”,由于快速排序是不稳定的排序,因此在流水线那个图中会出现不均匀的时间块,影响总体性能。


他想了一下,点点头。问,还有吗?给你个提示吧,你想一想加了这个优化以后,某个资源会不会出问题?


我想了想,“资源”,计算机的资源没几样啊,CPU,内存。。。再一次,瞬间恍然大明白,是内存出的问题,由于,若是并行进行的话,打个比方,好比如今同时处理的过程是,第一个2G数据的“T”阶段(由于第一个2G数据,比较早的进入流水线,因此以前的两个阶段已经处理完毕),第二个2G数据的“S”阶段,第三个2G数据的“L”阶段,那么这三个阶段是都须要把数据放到内存中的,因此一共得须要6G内存,可是目前计算机的实际内存只有2G啊!!!


解决方法很简单,将内存平均分为三份,分别用于处理三个阶段的数据。


这样带来的影响是,如今一次就不能处理2G数据了,只能处理2/3G的数据,流水线会加长。


他看这块处理的差很少了,就继续提示,你看看在最后的归并上有什么优化?


最后的归并就是不断在一组有序数列中找最小值,还用刚才那个例子,最后不是获得500个2G有序数列吗,可是扫描每一个文件头,找最小值,最差情形要比较500次,平均复杂度是O(n),n为最后获得的有序数组的个数,此例子为500。


他既然问有没有什么优化?那么必然是存在logn的算法了。一提logn和最小值,那没的说,必须是“堆”啊!!!


而后我给他说了一下具体实现细节


就是维护一个大小为n的“最小堆”,每次返回堆顶元素,就为当前全部文件头数值的那个最小值。而后根据刚才弹出的那个最小值是属于哪一个文件的,而后再将那个文件此时的头文件所指向的数,插入到最小堆中,文件指针自动后移。插入过程为logn复杂度,可是每次返回最小值的复杂度为O(1),运行时空间复杂度为O(n)。 OK,搞定。