我在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)
答案 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)
主要有两个原因:
写入频道有很大的开销。作为参考 - 我尝试使用channel和goroutines作为迭代器。它们比重复调用方法慢约100倍。当然,如果通过频道进行管道传输的操作需要很长时间才能执行(比如爬网页),那么差异可以忽略不计。
Goroutines真正为基于IO的并发性而发光,而对于CPU并行性则更少。
考虑到这两个问题,你需要大量的CPU或更长的时间,每个goroutine的阻塞操作更少,以加快速度。