我正在尝试使用go例程共享递归查找来并行化四叉树查找。
我的Quadtree结构如下:
type Quadtree struct {
Rectangle //Boundary of the quadtree
Points []Point
Ne *Quadtree
Se *Quadtree
Sw *Quadtree
Nw *Quadtree
Divided bool
Capacity int
Parent *Quadtree
}
我有一个名为QueryForNearestPoints
的方法,该方法接受Point
和searchRadius
并返回四叉树中searcharea
内的所有点。如果在给定的searchRadius
中找不到点,则增加searchRadius
并重试。
points
是将搜索半径中的点发送到的通道。我还使用sync.WaitGroup
wg
等待所有go例程结束。
func (q *Quadtree) QueryForNearestPoints(p Point, searchRadius float64) []QueryResult {
searcharea = Circle{p, searchRadius}
var testResults []QueryResult
for {
go func() {
loop:
for {
select {
case item, _ := <-points:
testResults = append(testResults, item)
case <-done:
break loop
}
}
}()
wg.Add(1)
go q.query(searcharea)
wg.Wait()
done <- true
if len(testResults) > 0 {
break
} else {
// Proportionally increase the search radius if no points are found.
searcharea = Circle{p, searcharea.Radius + searcharea.Radius*50/100}
}
}
return testResults
}
并行化四叉树的查询方法:
func (q *Quadtree) query(area Circle) {
defer wg.Done()
if !q.overlapsCircle(area) {
return
}
if len(q.Points) > 0 {
for i, point := range q.Points {
if area.contains(point) {
points <- QueryResult{point, i, q}
}
}
}
if q.Divided {
wg.Add(4)
go q.Ne.parallelquery(area)
go q.Se.parallelquery(area)
go q.Sw.parallelquery(area)
go q.Nw.parallelquery(area)
}
}
(q *Quadtree) parallelquery
方法:
func (q *Quadtree) parallelquery(area Circle) {
semaphore <- struct{}{}
defer func() {
<-semaphore
}()
q.query(area)
}
如果我没记错的话,这是一个CPU约束的工作负载,因此拥有1000个go-routine不会有帮助,所以我使用缓冲通道semaphore
作为计数信号量以确保在任何时候都只有n个go例程处于活动状态。(在这里我将n设置为4,因为我的计算机有4 cpus。)
唯一的问题是,这种方法比正常的非并行顺序方法要慢得多。我在这里想念什么?我怎样才能使它更快?
答案 0 :(得分:2)
这要慢得多,因为您在每个goroutine中所做的工作非常便宜,并且goroutine太多。
对于那些会在此答案中批评术语的人,我将互换使用并行性和并发性。即使严格地说,并行性是运行时/计算机的属性,并发性是代码的属性。如果某些代码在具有单个处理器的硬件上运行,则仍然可以并发,但是不会并行运行。
此处的并发版本较慢的原因是,使用通道等时仍需要进行一些同步。在幕后,通道使用互斥体来同步通道上的发送/接收。这意味着您正在引入goroutine之间的竞争。
每次调用parallelquery(area)
时,您都将启动另外4个必须调度的goroutine,但是(使用信号量通道)您将并发goroutine的数量限制为4。
在n次递归之后,您有4 ^ n个goroutine都试图从信号量通道接收值,这会引起很多争用。
对此使用阻塞CPU探查器,您可能会发现大部分执行时间都花在争用上,试图从信号量中获取令牌。