并行程序查找数列最小值所在下标

来源:互联网 发布:淘宝爱他美官方旗舰店 编辑:程序博客网 时间:2024/04/29 06:49
       

使用mpi设计一个并行程序来查找数列或多维数组中最小元素值,我相信只要搞个并行程序设计的人都会。但如果需要确定该最小元素值所在的下标,就有点小麻烦了。

以一维数组为例。

    最初的时候本人用了一个相当笨的方法,即在根进程创建两个长度为进程数的一维数组,分别用来存储通过收集操作从所有进程收集来的局部最小元素值及其对应的下标,再在根进程通过该一维数组串行查找全部最小值,对应的另一个一维数组就能得到小标了。

    如:miniDistance miniIndex分别是存储最小元素值及对应下标的两个一维数组,它们的值都是通过MPI_Gatherv操作收集局部最小值而得到的。如果在根进程得到miniDistance[i]是全局最小值,那么对应的miniIndex[i]就是该全局最小值对应的下标了。这种方法的缺点很明显,需要两次收集操作,在根进程串行查找全局最小值,进程多了,并行程序会很低。

    为了提高效率,可以创建一个结构体变量,包含两个元素,一个存储元素值,一个存储对应下标,这样只需要进行一次收集操作就能达到目的。但是,除了需要构造一个新mpi数据类型以便结构体数据的发送和接收外,仍然需要在根进程进行串行一维查找全局最小值,没有根本上解决问题。

    今天在测试程序的时候,突然想到可不可以把下标与元素值进行编码在一起形成另一个值,而保持原来元素值的相对大小不变,归约后再解码出下标?试了一下,结果很成功。举个例子:

    长度为100000的一维数组,其元素值取值范围在1100之间,那么,在各进程本地使用串行算法找到局部最小值后,将该最小值乘以100000,然后再加上该最小值所在下标,得到新值,然后根进程对新值进行归约,将得到的全局最小值对100000取模,就能得到全局最小值所在下标了。

我们来分析一下上面的做法为什么可行。因为数组长度为100000,所以下标取值范围为0-99999.而将元素值乘以100000后,至少大于等于100000,加上一个小于100000的下标值后,原来的元素值较大的仍然会保持相对较大。而在根进程对100000取模后,显然得到的就是前面加上去的那个小于100000的下标值了。使用这种方法通过一次归约操作就OK了,不再需要根进程另外的操作(除了一次取模操作)。效率提高是显然的。

    使用这种方法要注意元素值的范围,要保证下标值对元素值的相对大小没有影响,同时要保证运算后的新值不超过数据类型的取值范围。

  后来发现解决该问题的另一种方法。使用MPI_Allreduce函数。该函数能对只有两个元素的一维数组进行归约,就像MPI_Reduce归约单个元素一样,并且该函数归约后每个进程都得到归约后的结果,无需另外广播。我们知道该函数中的op参数,它表示要进行什么样的归约操作,有多个操作可选。如果选择MPI_MINLOC,则表示先对要归约的两元素数组的第一个元素进行最小化归约,即先按第一个元素进行比较取最小值,如果有多个进程的数组第一元素值相等,则再比较最二个元素,再取最小值。所以MPI_MINLOC操作叫做最小-最小操作。

  这样,如果数组的第一个元素保存元素值,第二个元素保存对应元素值的下标,那么,只需要一步归纳操作就完全可以达到我们的目的。

原创粉丝点击