我已经实现了一个函数contractGraph
,它使用随机收缩计算图的最小切割。我正在运行指定的次数并计算最小切割:
minCut := 0
for i := 0; i < totalCount; i++ {
_minCut := contractGraph(graph)
if minCut == 0 || _minCut < minCut {
minCut = _minCut
}
}
contractGraph
执行CPU密集型计算,但程序在我的计算机上只使用一个CPU核心。我想修改它,所以在任何时候发生contractGraph
的4次并行执行,结果被放入通道并同步读取并计算最小值。
我试过了:
func worker(graph Graph, i int, workerChan <- chan bool, minCutChan chan <- int) {
defer func () { <- workerChan }()
min_cut := contractGraph(graph)
minCutChan <- min_cut
}
func workerRunner(graph Graph, minCutChan chan int, totalCount int, workerCount int) {
workerChan := make(chan bool, workerCount)
for i := 0; i < totalCount; i++ {
go worker(graph, i, workerChan, minCutChan)
}
}
minCutChan := make(chan int)
go workerRunner(graph, minCutChan, totalCount, 4)
// read the resulting min cuts
minCut := 0
for _minCut := range minCutChan {
if minCut == 0 || _minCut < minCut {
minCut = _minCut
}
}
但仍然只使用了一个核心而且我最终得到了:
fatal error: all goroutines are asleep - deadlock!
此外,我不想使用频道,我认为应该只有一个频道可以获得结果。
您建议使用哪种模式?
答案 0 :(得分:4)
您忘记关闭minCutChan
,因此main
已陷入范围,并且所有常规例程都已完成。
不使用您可以使用的频道sync.WaitGroup
编辑:要处理totalCount,我会使用atomic.AddInt64
查看新更新的示例:
请参阅这些编辑的工作模拟示例:http://play.golang.org/p/WyCQrWK5aa
package main
import (
"fmt"
"sync"
"sync/atomic"
)
type Graph struct {
}
func contractGraph(Graph) int { return 0 }
func worker(wg *sync.WaitGroup, graph Graph, i int, minCutChan chan<- int) {
defer wg.Done()
for {
count := atomic.AddInt64(&totalCount, -1)
if count < 0 {
break
}
fmt.Println("Worker Iteration", count)
min_cut := contractGraph(graph)
minCutChan <- min_cut
}
}
func workerRunner(graph Graph, minCutChan chan int, workerCount int) {
wg := new(sync.WaitGroup)
wg.Add(workerCount)
for i := 0; i < workerCount; i++ {
go worker(wg, graph, i, minCutChan)
}
wg.Wait()
close(minCutChan)
}
var totalCount int64
func main() {
workerCount := 4
graph := Graph{}
totalCount = 100
minCutChan := make(chan int, workerCount+1)
go workerRunner(graph, minCutChan, workerCount)
go func() {
}()
// read the resulting min cuts
minCut := 0
for _minCut := range minCutChan {
if minCut == 0 || _minCut < minCut {
minCut = _minCut
}
}
fmt.Println(minCut)
}
更进一步的风格是在匿名函数中旋转工作者:
http://play.golang.org/p/nT0uUutQyS
package main
import (
"fmt"
"sync"
"sync/atomic"
)
type Graph struct {
}
func contractGraph(Graph) int { return 0 }
var totalCount int64
func workerRunner(graph Graph, minCutChan chan int, workerCount int) {
var wg sync.WaitGroup
wg.Add(workerCount)
for i := 0; i < workerCount; i++ {
go func() {
defer wg.Done()
for {
count := atomic.AddInt64(&totalCount, -1)
if count < 0 {
break
}
fmt.Println("Worker Iteration", count)
min_cut := contractGraph(graph)
minCutChan <- min_cut
}
}()
}
wg.Wait()
close(minCutChan)
}
func main() {
workerCount := 4
totalCount = 100
graph := Graph{}
minCutChan := make(chan int, workerCount+1)
go workerRunner(graph, minCutChan, workerCount)
// read the resulting min cuts
minCut := 0
for _minCut := range minCutChan {
if minCut == 0 || _minCut < minCut {
minCut = _minCut
}
}
fmt.Println(minCut)
}