2 回答
TA贡献2011条经验 获得超2个赞
一般的答案是线程间协调是有成本的,因此将任务发送到另一个 goroutine 只能在任务至少达到特定大小时加快速度。所以不要寄单件。
对于像快速排序这样的分而治之的算法,并行化的方法可能很有趣。通常:当您递归时,如果它足够大,您可以在 goroutine 中启动“对数组的一半进行排序”任务。“如果它足够大”部分是如何减少协调开销。
更详细地说,这看起来像:
写一个非平行
qsort(data []int)
更改
qsort
为可选地采用*sync.WaitGroup
我们将调用wg
的信号,表明它已完成。if wg != nil { wg.Done() }
在它return
的每个s之前添加。哪里
qsort
递归,让它检查它要排序的数据的一半是否很大(比如,超过 500 个项目?),和如果它很大,请开始另一个任务:
wg.Add(1); go qsort(half, wg)
如果不是,请在这里和现在排序:
qsort(half, nil)
换行
qsort
以对用户隐藏并行机制:like、havequicksort(data)
dowg := new(sync.WaitGroup)
、do an initialwg.Add(1)
、callqsort(data, wg)
和 dowg.Wait()
以等待所有后台排序完成。
这不是最佳策略,因为即使在有足够多的任务让您的核心保持忙碌之后,它仍会继续分叉新的 goroutine。关于如何将某些任务交给后台处理,您可以进行很多调整。但重要的一点是,仅对大型子任务使用另一个线程是一种并行化快速排序而不会被协调开销破坏的方法。
这是一个带有令人尴尬的草率快速排序的演示(您已在本地运行它以获取时间)-错误的可能性很大,绝对是已排序数据的二次方;关键是要理解并行分而治之的想法。
还有一种自下而上的策略——先对片段进行排序,然后再合并——例如,在这个并行排序包中使用。但是,包使用的就地合并代码很棘手。
(如果您还没有设置 GOMAXPROCS,请使用类似runtime.GOMAXPROCS(runtime.NumCPU())
in 的内容进行设置main
。)
最后看一下 Go 的 sort 包。有很多代码,但很清楚,一旦你得到它,你就可以用一个“真实的”、充实的排序实现来做你的实验。
TA贡献1797条经验 获得超6个赞
原来这很简单。当我在一台新机器上时,没有设置 GOMAXPROCS 变量。
正如预测的那样,新的基准测试有利于并行实现:设置为内核数量的两倍:
Using 16 goroutines
Ran 100 times
Non parallel average - 1980
Parallel average - 1133
设置为核心数:
Using 8 goroutines
Ran 100 times
Non parallel average - 2004
Parallel average - 1197
顺便说一下,这是相当一致的。双核数量的平均值总是好一点。
更大集合的基准(1000000):
Using 8 goroutines
Ran 100 times
Non parallel average - 3748
Parallel average - 2265
带双:
Using 16 goroutines
Ran 100 times
Non parallel average - 3817
Parallel average - 2012
- 2 回答
- 0 关注
- 185 浏览
添加回答
举报