使用goroutines与普通Mergesort合并排序

时间:2014-04-03 22:29:03

标签: sorting go mergesort goroutine

我在Go中写了两个版本的mergesort。一个有goroutines而另一个没有。我正在比较每个人的表现,我一直在看

https://github.com/denniss/goplayground/blob/master/src/example/sort.go#L69

那是使用goroutines的那个。这是没有

的人

https://github.com/denniss/goplayground/blob/master/src/example/sort.go#L8

我一直试图弄清楚为什么goroutine实现比没有实现更糟糕。这是我在当地看到的号码

 go run src/main.go
[5 4 3 2 1]
Normal Mergesort
[1 2 3 4 5]
Time:  724
Mergesort with Goroutines
[1 2 3 4 5]
Time:  26690

然而,我仍然无法找出原因。想知道你们是否可以给我关于做什么/看什么的建议或想法。在我看来,使用goroutines的实现应该至少在某种程度上更好。我这么说主要是因为以下几行

go MergeSortAsync(numbers[0:m], lchan)
go MergeSortAsync(numbers[m:l], rchan)

3 个答案:

答案 0 :(得分:1)

使用并发并不一定能使算法运行得更快。实际上,除非算法本质上是并行的,否则会降低执行速度。

处理器(CPU)一次只能做一件事,即使对我们来说,它似乎同时做了两件事。两个goroutine的指令可能是交错的,但这并不能使它们比单个goroutine运行得更快。来自其中一个goroutine的单条指令在任何给定时刻都会被执行(根据硬件特性,有一些非常低级别的例外) - 除非你的程序在多个核心上运行。

据我所知,标准合并排序算法并不是固有的并行; some modifications need to be made优化它以便在多个处理器上并行执行。即使您使用多个处理器,也需要针对它优化算法。

这些优化通常与渠道的使用有关。我不同意#34;写频道有很大的开销"它本身(Go使它非常高效),然而,它确实引入了goroutine阻塞的可能性。它并不是对频道的实际写入,它会大大减慢程序的速度,它会调度/同步:goroutine等待和唤醒从频道写入或读取可能是瓶颈。

为了补充Not_a_Golfer的答案,我同意goroutines在执行I / O操作时肯定会闪耀 - 即使在单核上 - 因为它们远离CPU。当一个goroutine正在等待I / O时,调度程序可以调度另一个CPU绑定的goroutine来同时运行。但是,当在多个处理器/核心上部署时,goroutine也会为CPU密集型操作提供支持。

答案 1 :(得分:1)

正如其他人所解释的那样,存在并行成本。您需要看到足够的好处来弥补成本。只有当工作单位大于制作频道和goroutines接收结果的成本时才会发生这种情况。

您可以尝试确定工作单​​元应该是什么。假设工作单元正在排序1000个元素。在这种情况下,您可以非常轻松地更改代码:

func MergeSortAsync(numbers [] int, resultChan chan []int)  {
    l := len(numbers)
    if l <= 1000 {
            resultChan <- Mergesort(numbers)
            return
    }

换句话说,一旦工作单元太小而无法使用goroutines和渠道,请使用简单的Mergesort,而无需支付这些费用。

答案 2 :(得分:0)

主要有两个原因:

  1. 写入频道有很大的开销。作为参考 - 我尝试使用channel和goroutines作为迭代器。它们比重复调用方法慢约100倍。当然,如果通过频道进行管道传输的操作需要很长时间才能执行(比如爬网页),那么差异可以忽略不计。

  2. Goroutines真正为基于IO的并发性而发光,而对于CPU并行性则更少。

  3. 考虑到这两个问题,你需要大量的CPU或更长的时间,每个goroutine的阻塞操作更少,以加快速度。