Multithreading 如何在合并排序中多线程执行合并操作?

Multithreading 如何在合并排序中多线程执行合并操作?,multithreading,algorithm,sorting,mergesort,Multithreading,Algorithm,Sorting,Mergesort,在我所看到的merge-sort的多线程版本中,多线程通常是在左侧和右侧子数组的递归过程中完成的(即,每个线程都分配了自己的子数组来处理),合并操作是在每个线程完成各自的工作后由主线程完成的 我想知道是否有一种很好的方法可以对合并2个排序子数组的最终合并操作进行多线程处理?如果是这样的话,怎么做呢?实际上有一种方法可以将合并任务拆分为两个并发线程: 两个子阵列排序后 将任务分配给一个线程,以将已排序子数组的开头的元素合并到目标数组的前半部分,然后 为另一个线程分配一个不同但互补的任务:从已排序

在我所看到的merge-sort的多线程版本中,多线程通常是在左侧和右侧子数组的递归过程中完成的(即,每个线程都分配了自己的子数组来处理),合并操作是在每个线程完成各自的工作后由主线程完成的


我想知道是否有一种很好的方法可以对合并2个排序子数组的最终合并操作进行多线程处理?如果是这样的话,怎么做呢?

实际上有一种方法可以将合并任务拆分为两个并发线程:

  • 两个子阵列排序后
  • 将任务分配给一个线程,以将已排序子数组的开头的元素合并到目标数组的前半部分,然后
  • 为另一个线程分配一个不同但互补的任务:从已排序子数组的末尾合并到目标数组的后半部分,从末尾开始
  • 您必须仔细编写这些合并函数,以便排序保持稳定,并且每个线程应该只写入目标数组的一半,可能会从已排序的子数组中读取相同的元素,但选择不同的元素

我还没有在关于多线程合并排序的文献中看到过这种方法。我想知道它的性能是否比经典的实现更好。

与任何多线程执行的任务一样,您需要拆分任务并将其分发到不同的线程。顺便说一句:你问的是/不是问题。@UlrichEckhardt:OP也在问如何做到这一点。这个想法很有趣。因此,我们没有将每个线程分配给已排序的子数组,而是将1个线程分配给最终数组的前半部分,将另外2个线程分配给最终数组的后半部分。然后,线程1对两个排序的子数组进行操作,并合并元素,直到最后一个数组的前半部分被填充,线程2执行类似的工作,但最后一个数组的后半部分除外。而且,由于两个线程都只是读取已排序子数组的元素,我们应该不受争用条件的影响?@ananuser01:是的,这是一个可能的实现,但要小心:当完成排序时,线程必须同步,因为在两半完全排序之前,合并无法开始。此外,第二个线程使用了一种不同的合并算法,该算法在已排序的一半和目标数组上从高索引值开始向下操作,并在中间点停止。@chqrlie-在前面的问题中,我使用了我发布的Windows本机线程采用了另一种方法。对于k个线程,代码将数组拆分为k个部分,每个线程对其部分进行排序,然后k/2个线程合并k个部分的对,然后k/4个线程合并2k个部分的对。在一个拥有4个超线程内核的3770K旧cpu上,4个线程的速度快了大约3倍,8个线程的速度快了3.9倍,显然,达到了收益递减的程度。我怀疑核心本地缓存是一个因素。@chqrlie-继续,我可以试试你的想法,将k个部分与k个线程合并,前后合并。在一般情况下,这可能更快。最坏的情况是反向排序数据,其中左排序子数组的第一个元素大于右排序子数组的最后一个元素,两个线程都将读取第二个子数组的每个元素,“转发”线程将右排序子数组复制到合并数组的左半部分“向后“线程将左子数组复制到合并数组的右半部分。@rcgldr:我不确定这是否是最坏的情况,因为两个踏板将继续从同一个已排序的子数组复制,分支预测将非常有效,可能使其成为合并的最佳情况,以及直接排序的数据。”。期待您的基准测试结果。