在多个线程中运行一个函数

时间:2014-06-03 07:18:23

标签: go

我已经实现了一个函数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!

此外,我不想使用频道,我认为应该只有一个频道可以获得结果。

您建议使用哪种模式?

1 个答案:

答案 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)
}